Form Validation not happening for Django model form - django

I have created the following model form and I want to apply validation on it but it is not working. Can anyone please tell me what mistake I am making?
"""class used for booking a time slot."""
class BookingForm(forms.ModelForm):
class Meta:
model = Booking
fields = ['check_in_date', 'check_in_time', 'check_out_time',
'person', 'no_of_rooms']
"""Function to check if username and password match or not."""
def clean(self):
cleaned_data = super().clean()
normal_book_date = cleaned_data.get("check_in_date")
normal_check_in = cleaned_data.get("check_in_time")
if (normal_book_date < now.date() or
(normal_book_date == now.date() and
normal_check_in < now.time())):
#self._errors['check_in_date'] = self.error_class([
# 'You can only book for future.])
raise ValidationError(
"You can only book for future."
)
return cleaned_data
Edit:
Here is the template that I am rendering. I want to show the error in the template itself. Like how real forms work and show errror.
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Booking</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Raleway">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="{% static 'hotel/css/base.css' %}">
<style>
*{
padding: 0;
margin: 0;
}
</style>
</head>
<body id="body-color">
<div class="container2" id="boxx">
<h2 class="w3-center">Room Slot Booking</h2><br/>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class= "submit submit-right" value="Search Availability" />
</form>
<br/>
</div>
</body>
</html>
Here is the views.py file
"""Function to return the available categories."""
#login_required(login_url="/hotel/signin/")
def booking(request):
if request.method == 'POST':
form = BookingForm(request.POST)
if form.is_valid():
request.session['normal_book_date'] = request.POST['check_in_date']
normal_book_date = convert_to_date(request.session['normal_book_date'])
request.session['normal_check_in'] = request.POST['check_in_time']
normal_check_in = convert_to_time(request.session['normal_check_in'])
request.session['normal_check_out'] = request.POST['check_out_time']
# now is the date and time on which the user is booking.
if (normal_book_date > now.date() or
(normal_book_date == now.date() and
normal_check_in >= now.time())):
request.session['normal_person'] = int(request.POST['person'])
request.session['normal_no_of_rooms_required'] = int(
request.POST['no_of_rooms']
)
normal_check_out = convert_to_time(request.session['normal_check_out'])
response = list()
response = search_availability(True,
normal_book_date,
normal_check_in,
normal_check_out,
request.session['normal_person'],
request.session['normal_no_of_rooms_required'])
if response:
context = {
'categories': response,
'username': request.session['normal_username']
}
return render(request, 'categories.html', context)
return HttpResponse("Not Available")
else:
context = {
'form': BookingForm(),
'username': request.session['normal_username']
}
return render(request, 'book.html', context)
else:
context = {
'form': BookingForm(),
'username': request.session['normal_username']
}
return render(request, 'book.html', context)
context = {
'form': BookingForm(),
'username': request.session['normal_username']
}
return render(request, 'book.html', context)

Just override the is_valid() instead of the clean.. That's where I've found success
"""class used for booking a time slot."""
class BookingForm(forms.ModelForm):
class Meta:
model = Booking
fields = ['check_in_date', 'check_in_time', 'check_out_time',
'person', 'no_of_rooms']
"""Function to check if username and password match or not."""
def is_valid(self):
valid = super(BookingForm, self).is_valid()
# ^ valid is a Boolean
# Note: added self to cleaned_data.get()
normal_book_date = self.cleaned_data.get("check_in_date")
normal_check_in = self.cleaned_data.get("check_in_time")
if (normal_book_date < now.date() or
(normal_book_date == now.date() and
normal_check_in < now.time())):
valid = False
# Not sure if this works, or is needed (the "raise" part mostly)
# if it doesn't work just add the error to the field instead (see below)
raise ValidationError(
"You can only book for future."
)
# You could also add the error msg per field & it will render it
# - extra tidbit
self.add_error('normal_book_date', 'You can only book for future.')
return valid
That is_valid is called when you do form.is_valid() in the view, so make sure you're doing that too
Edit
Here's how you would pass the failed form to the render. You just pass that form variable instead of init a new BookingForm()
Not only will it show the Errors, but it will keep the fields filled with whatever you submitted (instead of clearing the entire form)
view.py
"""Function to return the available categories."""
#login_required(login_url="/hotel/signin/")
def booking(request):
if request.method == 'POST':
form = BookingForm(request.POST)
if form.is_valid():
request.session['normal_book_date'] = request.POST['check_in_date']
normal_book_date = convert_to_date(request.session['normal_book_date'])
request.session['normal_check_in'] = request.POST['check_in_time']
normal_check_in = convert_to_time(request.session['normal_check_in'])
request.session['normal_check_out'] = request.POST['check_out_time']
# This should be in the form.is_valid() & removes an else
#
# now is the date and time on which the user is booking.
# if (normal_book_date > now.date() or
# (normal_book_date == now.date() and
# normal_check_in >= now.time())):
request.session['normal_person'] = int(request.POST['person'])
request.session['normal_no_of_rooms_required'] = int(
request.POST['no_of_rooms']
)
normal_check_out = convert_to_time(request.session['normal_check_out'])
response = list()
response = search_availability(True,
normal_book_date,
normal_check_in,
normal_check_out,
request.session['normal_person'],
request.session['normal_no_of_rooms_required'])
if response:
# Success!
context = {
'categories': response,
'username': request.session['normal_username']
}
return render(request, 'categories.html', context)
# no availability
return HttpResponse("Not Available")
else:
context = {
'form': form, # <- pass the failed form to the render
'username': request.session['normal_username']
}
return render(request, 'book.html', context)
context = {
'form': BookingForm(),
'username': request.session['normal_username']
}
return render(request, 'book.html', context)
To really clean it up and remove some extra else you could only use a single form variable
view.py (condensed)
"""Function to return the available categories."""
#login_required(login_url="/hotel/signin/")
def booking(request):
# Init the form - This will either:
# a) init a new form (if no POST)
# b) fill form with POST data
form = BookingForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
request.session['normal_book_date'] = request.POST['check_in_date']
normal_book_date = convert_to_date(request.session['normal_book_date'])
request.session['normal_check_in'] = request.POST['check_in_time']
normal_check_in = convert_to_time(request.session['normal_check_in'])
request.session['normal_check_out'] = request.POST['check_out_time']
request.session['normal_person'] = int(request.POST['person'])
request.session['normal_no_of_rooms_required'] = int(
request.POST['no_of_rooms']
)
normal_check_out = convert_to_time(request.session['normal_check_out'])
response = list()
response = search_availability(True,
normal_book_date,
normal_check_in,
normal_check_out,
request.session['normal_person'],
request.session['normal_no_of_rooms_required'])
if response:
# Success!
context = {
'categories': response,
'username': request.session['normal_username']
}
return render(request, 'categories.html', context)
# no availability
return HttpResponse("Not Available")
# Implied else, form failed is_valid and `form` now has the .errors attribute
# (will render the page with it)
context = {
'form': form,
'username': request.session['normal_username']
}
return render(request, 'book.html', context)

Related

Add customer modal and edit in one view in django

I am kinda like stuck.
I have a BankAccountCreation() and the the form is called in a modal in Django template.
I am trying to get the same for be used for editing. but when I do that my edit button returns an empty form
My view is as below
def employee_info(request, id):
if not request.user.is_authenticated:
return redirect('/')
context = {}
banks = Bank.objects.all()
employee = get_object_or_404(Employee, id = id)
bank_instance = Bank.objects.filter(employee = employee).first()
context = {}
context['employee'] = employee
context['bank'] = bank_instance
context['banks'] = banks
context['title'] = 'profile - {0}'.format(employee.get_full_name)
if request.method == 'GET':
form = BankAccountCreation()
context['form'] = form
return render(request, 'employee/employee_info.html', context)
if request.method == 'POST':
form = BankAccountCreation(data = request.POST)
if form.is_valid():
instance = form.save(commit = False)
employee_id = request.POST.get('employee')
employee_object = employee
instance.employee = employee_object
instance.name = request.POST.get('name')
instance.branch = request.POST.get('branch')
instance.account = request.POST.get('account')
instance.code = request.POST.get('code')
instance.save()
messages.success(request, 'Bank Details Successfully Created for {0}'.format(employee_object.get_full_name), extra_tags = 'alert alert-success alert-dismissible show')
return redirect('employee_info', id=employee.id)
else:
context['form'] = form
messages.error(request, 'Error Updating details for {0}'.format(employee_object.get_full_name), extra_tags = 'alert alert-warning alert-dismissible show')
return redirect('employee_info', id=employee.id)
form = BankAccountCreation()
return render(request, 'employee/employee_info.html', context)
The Bank model has a foreign key to the Employee model

How to access child model from parent model in Python

I am trying to get data from child model through the parent model, I don't know if it possible or there is a way of doing it, and I want to know how to implement the formset concept in this context , I would be grateful for any solution
models.py
class Client_Data(models.Model):
RC = models.CharField(max_length=50)
Raison_social = models.CharField(max_length=254)
NIF = models.CharField(max_length=50,unique=True)
AI = models.CharField(max_length=50,unique=True)
NIS = models.CharField(max_length=50,unique=True)
Banque = models.CharField(max_length=50,unique=True)
CB = models.CharField(max_length=50)
adresse = models.CharField(max_length=50)
slug = models.SlugField(blank=True, unique=True)
active = models.BooleanField(default=True)
class Contact(models.Model):
client = models.ForeignKey(Client_Data,blank=True,on_delete=models.CASCADE)
Nom = models.CharField(max_length=50)
post = models.CharField(max_length=50)
Tel = models.CharField(max_length=50)
email = models.EmailField(max_length=255,unique=True)
contact_type = models.CharField(default='Client_contact',max_length=50)
views.py
def save_client_form(request, form,Contact_form, template_name):
data = dict()
if request.method == 'POST':
if form.is_valid() and Contact_form.is_valid():
client = form.save()
contact = Contact_form.save(commit=False)
contact.client = client
contact.save()
form.save()
Contact_form.save()
data['form_is_valid'] = True
books = Client_Data.objects.all()
data['html_book_list'] = render_to_string('Client_Section/partial_client_c.html', {
'client': books
})
else:
print(form.errors)
print(Contact_form.errors)
data['form_is_valid'] = False
context = {'form': form,'contact_form':Contact_form}
data['html_form'] = render_to_string(template_name, context, request=request)
return JsonResponse(data)
def client_update(request,slug):
book = get_object_or_404(Client_Data, slug=slug)
contact = Contact.objects.select_related().filter(client=book.id)
print(contact)
if request.method == 'POST':
form = ClientForm(request.POST, instance=book)
contact_form = Contact_Form(request.POST, instance=contact)
else:
form = ClientForm(instance=book)
contact_form = Contact_Form(instance=contact)
return save_client_form(request, form,contact_form ,'Client_Section/partial_client_update.html')
If I understand you correctly, you may simply do it this way:
contact = Contact.objects.select_related().filter(client=book.id)
addresse = contact.client.addresse
in you view.py
from django.forms import inlineformset_factory
from django.shortcuts import render, get_object_or_404
def client_update(request, slug):
context = {}
book = get_object_or_404(Client_Data, slug=slug)
formset = inlineformset_factory(Client_Data, Contact, form=Contact_Form )
if request.method == 'POST':
form = ClientForm(request.POST, instance=book)
contactforms = formset(request.POST, prefix='contactformset', instance=book)
context['form'] = form
context['contactforms'] = contactforms
if contactforms.is_valid() and form.is_valid():
form.save()
contactforms.save()
return HttpResponse("your data saved")
else:
return render(request, 'Client_Section/partial_client_update.html', context)
else:
form = ClientForm(instance=book)
contactforms = formset(prefix='contactformset', instance=book)
context['form'] = form
context['contactforms'] = contactforms
return render(request, 'Client_Section/partial_client_update.html', context)
in partial_client_update.html
<form method="POST">
{% csrf_token %}
{{form}}
<hr>
{% formset in contactforms %}
{{formset }}
<hr>
{% endfor %}
<button type="submit ">update</button>
</form>

How to open an uploaded file in another template - Django?

my django app acts as an emailing service, emails that are sent are view-able and it's possible to send html emails. How do I display the html emails on the view-mail page rather than just displaying the name of the file ? (the following is the mail-view for an html email):
How would I display the actual html in the body of this page?
This is my views.py:
def outbox(request):
#Mail_Item.objects.all().delete()
if request.method == "POST" and request.POST.get('Username', False)!=False:
username = request.POST.get('Username')
password = request.POST.get('Password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user, backend='django.contrib.auth.backends.ModelBackend')
print(username + " has logged in")
messages = Mail_Item.objects.filter(user=request.user.username)
args = {'messages':messages}
return render(request, 'outbox.html', args)
else:
return render(request, '404.html')
elif request.POST.get('Username', False) == False and request.POST.get('mail_body_field', False) == False:
pass
elif request.method == "POST" and request.POST.get('mail_subject_field')!=False:
subject = request.POST.get('mail_subject_field')
body = request.POST['mail_body_field']
file = ""
try:
file = request.FILES['filename']
except:
pass
print("sending mail:")
for i in range(1, len(Res)+1):
y = Res['ID' + str(i)].email
print("sent to " + y )
msg = EmailMessage(subject, body, 'email#example.com', [y])
msg.content_subtype = "html"
if (str(file)) != "" and (str(file))[-4:] != 'html':
msg.attach_file(str(file))
obj = Mail_Item(subject=subject, body=body, user=request.user.username, file_name=(str(file)))
obj.save()
print("email stored in database")
elif (str(file)) != "" and (str(file))[-4:] == 'html' :
uploaded_file = file
fs = FileSystemStorage()
fs.save((str(file)), uploaded_file)
html_message = render_to_string((str(file)), {'context': 'values'})
plain_message = strip_tags(html_message)
from_email = 'From <email2#example.com>'
mail.send_mail(subject, plain_message, from_email, [y], html_message=html_message)
obj = Mail_Item(subject=subject, body=body, user=request.user.username, file_name=(str(file)))
obj.save()
else:
obj = Mail_Item(subject=subject, body=body, user=request.user.username, file_name='None')
obj.save()
print("email stored in database")
#msg.send()
i += 1
messages = Mail_Item.objects.filter(user=request.user.username)
args = {'messages':messages}
return HttpResponseRedirect('../templates/outbox.html', args, request)
else:
print("pleeeeeaassee")
return render(request, '404.html')
messages = Mail_Item.objects.filter(user=request.user.username)
args = {'messages':messages}
return render(request, 'outbox.html', args)
def login_page(request):
if request.method == "POST":
username = request.POST['sign-up-name']
email = request.POST['sign-up-email']
password = request.POST['sign-up-password']
user = User.objects.create_user(username, email, password)
user.save()
print(username + " has been added to the user database.")
else:
pass
return render(request, 'login.html')
def signup_page(request):
return render(request, 'signup.html')
def mail_view(request, id=None):
if id:
email = Mail_Item.objects.get(id=id)
args = {'email':email}
else:
pass
return render(request, 'mail-view.html', args)
def log_out(request):
logout(request)
return render(request, 'log-out.html')
def delete(request):
Mail_Item.objects.filter(id=id).delete()
messages = Mail_Item.objects.filter(user=request.user.username)
args = {'messages':messages}
return render(request, 'outbox.html', args)
This is the code for my mail-view template where I'd like to place the html that is being sent:
<div class="mail-view">
<h4 class="m-0">{{ email.subject }}</h4>
<div class="divid"></div>
<div class="media">
<div class="media-left">
<div class="avatar avatar-lg avatar-circle">
<img class="img-responsive" src="{% static '../static/assets/images/221.jpg' %}" alt="avatar"/>
</div><!-- .avatar -->
</div>
<div class="media-body">
<div class="m-b-sm">
<h4 class="m-0 inline-block m-r-lg">
Access Bank
</h4>
</div>
<p><b>Attachment: </b>{{ email.file_name }}</p>
</div>
</div>
<div class="divid"></div>
<div class="row">
<div class="col-md-12">
<div class="m-h-lg lh-xl">
<p>{{ email.body }}</p>
</div>
</div>
</div>
</div>
Models.py:
from django.db import models
class Details(models.Model):
email = models.CharField(max_length=200)
def __str__(self):
return self.email
class Mail_Item(models.Model):
subject = models.CharField(max_length=200)
body = models.CharField(max_length=300)
time = models.DateTimeField(auto_now=True)
user = models.CharField(max_length=15)
file_name = models.CharField(max_length=100, null=True, default=None)
def __str__(self):
template = '{0.subject} {0.body} {0.time} {0.user} {0.file_name}'
return template.format(self)

In Django Bootstrap 4, how to avoid rendering an alert with form errors?

I'm using django-bootstrap4 (https://django-bootstrap4.readthedocs.io/en/latest/) in a project and find that when there are errors in a form, an alert box shows up with a list of the errors. In my case, this is problematic because the errors are repeated:
I've had a look at the FormRenderer source code, and I don't see a way I can opt out of displaying this 'alert of errors':
class FormRenderer(BaseRenderer):
"""
Default form renderer
"""
def __init__(self, form, *args, **kwargs):
if not isinstance(form, BaseForm):
raise BootstrapError(
'Parameter "form" should contain a valid Django Form.')
self.form = form
super(FormRenderer, self).__init__(*args, **kwargs)
self.error_css_class = kwargs.get('error_css_class', None)
self.required_css_class = kwargs.get('required_css_class', None)
self.bound_css_class = kwargs.get('bound_css_class', None)
def render_fields(self):
rendered_fields = []
for field in self.form:
rendered_fields.append(render_field(
field,
layout=self.layout,
form_group_class=self.form_group_class,
field_class=self.field_class,
label_class=self.label_class,
show_label=self.show_label,
show_help=self.show_help,
exclude=self.exclude,
set_placeholder=self.set_placeholder,
size=self.size,
horizontal_label_class=self.horizontal_label_class,
horizontal_field_class=self.horizontal_field_class,
error_css_class=self.error_css_class,
required_css_class=self.required_css_class,
bound_css_class=self.bound_css_class,
))
return '\n'.join(rendered_fields)
def get_fields_errors(self):
form_errors = []
for field in self.form:
if not field.is_hidden and field.errors:
form_errors += field.errors
return form_errors
def render_errors(self, type='all'):
form_errors = None
if type == 'all':
form_errors = self.get_fields_errors() + self.form.non_field_errors()
elif type == 'fields':
form_errors = self.get_fields_errors()
elif type == 'non_fields':
form_errors = self.form.non_field_errors()
if form_errors:
return render_template_file(
'bootstrap4/form_errors.html',
context={
'errors': form_errors,
'form': self.form,
'layout': self.layout,
'type': type,
}
)
return ''
def _render(self):
return self.render_errors() + self.render_fields()
This is because the _render() method always shows both self.render_errors() and self.render_fields() (cf. https://github.com/zostera/django-bootstrap4/blob/ead5d4d06547b93aa49d40fac88c9de42fefda34/bootstrap4/renderers.py#L216-L217).
How do I prevent this repetition of errors (by disabling the alert box)?

Django Can't save form data on database

I'm trying write a small app while I'm learning django.However, when I try to save the form data in database, some problems happen to me.I use python3.4 and django 1.8.4, my database is MySql
The first problem I met is that the database doesn't have any data
this is my model code:
SUBJECT_CHOICES = (
('computerscience', '计算机科学导论'),
('C-sharp', 'C#'),
('cplusplus', 'C++'),
('CCNA', 'CCNA'),
('ACM', 'ACM'),
('linux', 'linux'),
('java', 'java'),
('python', 'python')
)
class Homework(models.Model):
handin_date = models.DateTimeField('交作业时间')
subject = models.CharField(verbose_name = '课程', default = '计算机科学导论', max_length = 20, choices = SUBJECT_CHOICES)
code = models.TextField(verbose_name = '代码', default = '')
xuehao = models.CharField(verbose_name = '学号', default = '', max_length = 9)
name = models.CharField(verbose_name = '姓名', default = '', max_length = 10)
this is my view code:
def cshomework(request):
if request.method == 'POST':
form = HomeworkForm(request.POST)
if form.is_valid():
return render(request, 'blog/success.html', { 'title': '交作业成功' })
else:
form = HomeworkForm(initial = { 'xuehao': '学号', 'name': '姓名', 'subject': '计算机科学导论', 'handin_date': dt.now(), 'code': '你的代码' })
return render(request, 'blog/cshomework.html', { 'title': '交作业', 'form': form })
In this way there's nothing in my database
The seconde question is when I tried another way, I get a None value in my datebase
The same model code as before
Here is my view code:
def cshomework(request):
if request.method == 'POST':
form = HomeworkForm(request.POST)
if form.is_valid():
return render(request, 'blog/success.html', { 'title': '交作业成功' })
else:
homework = Homework.objects.create(xuehao = '学号', name = '姓名', subject = '计算机科学导论', handin_date = dt.now(), code = '你的代码')
form = HomeworkForm(instance = homework)
return render(request, 'blog/cshomework.html', { 'title': '交作业', 'form': form })
the '课程' means 'subject'
How can I deal with these problems?
I' really appriciate your help!
After all check if form.is_valid(), you need save the form.
def cshomework(request):
if request.method == 'POST':
form = HomeworkForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'blog/success.html', { 'title': '交作业成功' })
else:
form = HomeworkForm(initial = { 'xuehao': '学号', 'name': '姓名', 'subject': '计算机科学导论', 'handin_date': dt.now(), 'code': '你的代码' })
return render(request, 'blog/cshomework.html', { 'title': '交作业', 'form': form })
At the second way, you are creating a new HomeWork everytime a URL is accessed, without submit any post data.