How can I raise ValidationError using DjangoForm? - python

I am quite new to programming and I am trying to build my first webiste!
I am trying to validate some fields of a form on server side and I cannot understand why it is not displayed to the user on HTML page. I have tried the different approaches, but unsuccessfully. I know it is quite newbie question, but I cannot understand why it is not working.
forms.py
class SuggestionForm(forms.Form):
name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
text = forms.CharField(max_length=800, widget=forms.Textarea)
def clean_text(self):
data = self.cleaned_data['text']
print(data)
if len(data) < 50:
raise forms.ValidationError('The text cannot be smaller than 50 char')
return data
views.py
def suggestion_add(request):
if request.method == "POST":
form = SuggestionForm(request.POST)
if form.is_valid():
suggestion = Suggestions.objects.create(
name = form.cleaned_data['name'],
last_name = form.cleaned_data['last_name'],
text = form.cleaned_data['text']
)
suggestion.save()
return redirect("success")
else:
form = SuggestionForm()
form.fields['name'].widget.attrs.update({
'placeholder': 'Your name'
})
form.fields['last_name'].widget.attrs.update({
'placeholder': 'Your surname'
})
form.fields['text'].widget.attrs.update({
'placeholder': 'Your thoughts'
})
return render(request, "suggestions_add.html", {'form':form})
html
<form action="" enctype="multipart/form-data" method="post">
<div id='id_name' class="control-group">
<label for="id_name" class="control-label">
Name
</label>
<div class="controls">
{{ form.name }}
</div>
</div>
<div id='id_prenume' class="control-group">
<label for="id_prenume" class="control-label">
Last name
</label>
<div class="controls">
{{ form.last_name }}
</div>
</div>
<div id='id_text' class="control-group">
<label for="id_text" class="control-label">
Text
</label>
<div class="controls">
<label for="field"></label>
{{ form.text }}
</div>
<div class="characters">
<span id="charNum"> </span> <span id="charText"></span>
</div>
</div>
<div class="wrap-send">
<input type="submit" value="Send" class="drpbtn" id="send-sugestion">
</div>
{% csrf_token %}
</form>
I tried every approach I found on internet, and definitely something's up with my code because I cannot understand why it is not showing the error to the user!
Thank you so much for your time!

Because you do not render any errors. In order to render any errors, you should render not only the field but the errors as well. This is discussed in the rendering fields manually section of the documentation. For example for your text field you can render the errors with:
{% if form.text.errors %}
<ol>
{% for error in form.text.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
<div class="controls">
<label for="field"></label>
{{ form.text }}
</div>
You can of course add a different styling, etc.
You should do this for all form fields, since each field can raise errors.
Furthermore there can also be non-field errors: these are errors not related to a specific field, but often a combination of fields. These are typically rendered at the top of the form with something like:
{% if form.non_field_errors %}
<ol>
{% for error in form.non_field_errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}

Related

Django forms not returning result or errors

I am trying to use a Django form for a login page, but the form is returning False whenever I call form.is_valid(). I tried to print the errors in the console and in the HTML file but there's nothing displaying. I tried to get data from the form with form["email"].value() and it's returning None, even when I input data into the email field.
Here's views.py:
def postlogin(request):
form = BootstrapAuthenticationForm(request.POST)
# This prints out None into the console
print(form["email"].value())
if form.is_valid():
# This code never runs! Even when there are no errors in the form fields!
return render(request, "app/home.html")
# If form is invalid, return to login page
# This always runs, meaning form.is_valid() keeps being false!
return render(request,"app/login.html", {"form":form})
Here's my forms.py:
from django import forms
from django.contrib.auth.forms import AuthenticationForm
from django.utils.translation import ugettext_lazy as _
class BootstrapAuthenticationForm(AuthenticationForm):
"""Authentication form which uses boostrap CSS."""
email = forms.CharField(max_length=254,label=('Email'),
widget=forms.TextInput({
'class': 'form-control',
'placeholder': 'Email'}))
password = forms.CharField(label=("Password"),
widget=forms.PasswordInput({
'class': 'form-control',
'placeholder':'Password'}))
Here's my login.html:
{% extends "app/layout.html" %}
{% block content %}
<h2>{{ title }}</h2>
<div class="row">
<div class="col-md-8">
<section id="loginForm">
<form action="/postlogin/" method="post" class="form-horizontal">
{% csrf_token %}
<h4>Use a local account to log in.</h4>
<hr />
<div class="form-group">
<label for="id_username" class="col-md-2 control-label">{{form.email.label}}</label>
<div class="col-md-10">
{{ form.email }}
</div>
</div>
<div class="form-group">
<label for="id_password" class="col-md-2 control-label">{{form.password.label}}</label>
<div class="col-md-10">
{{ form.password }}
</div>
</div>
<div class="form-group">
<label for="id_password" class="col-md-2 control-label">{{form.test.label}}</label>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="hidden" name="next" value="/" />
<input type="submit" value="Log in" class="btn btn-default" />
</div>
</div>
<!-- Nothing below shows even when form.is_valid() is false -->
{% if form.errors %}
<p class="validation-summary-errors">Please enter a correct user name and password.</p>
{% endif %}
{% if form.non_field_errors %}
<p class="validation-summary-errors">Please enter a correct user name and password.</p>
{% endif %}
</form>
</section>
</div>
<div class="col-md-4">
<section id="socialLoginForm"></section>
</div>
</div>
<!-- Again, none of this shows in the HTML file even when form.is_valid() is False -->
{% for error_field, error_message in form.errors.items %}
{{ error_field|striptags }}: {{ error_message|striptags }}
{% endfor %}
{% endblock %}
if form.is_valid():
# after validating form you can print field value using (cleaned_data) method
print(form.cleaned_data['email'])
return render(request, "app/home.html")

ManagementForm data is missing or has been tampered with in django

I am using the following code in my django app which is working fine but i am getting this error when trying to save a form:
['ManagementForm data is missing or has been tampered with']
Views:
def employedit(request, pk, id):
employ_academic_forms = EmployAcademicUpdateFormSet(queryset=EmployAcademicInfo.objects.filter(employ_id=pk))
if request.method == 'POST':
employ_academic_forms = EmployAcademicUpdateFormSet(request.POST)
if employ_academic_forms.is_valid():
employ_academic_forms.save()
return redirect('employ-list')
context = {
'employ_academic_forms':employ_academic_forms,
}
return render(request, 'admins/employ/edit_employ.html', context)
form:
EmployAcademicUpdateFormSet = modelformset_factory(
EmployAcademicInfo,
exclude = ['employ_id'],
extra=0,
labels = {
'degree': 'Enter Employ Degree',
'last_passing_institution_name': 'Enter Employ Passing Institution',
'last_passing_year': 'Enter Employ Passing Year',
},
widgets = {
'degree' : forms.Select(attrs={'class':'form-control form-control-lg', 'placeholder':'Enter degree'}),
'last_passing_institution_name' : forms.TextInput(attrs={'class':'form-control form-control-lg', 'placeholder':'Enter institution name'}),
'last_passing_year' : forms.DateInput(attrs={'class':'form-control form-control-lg', 'type':'date'}),
},
)
Html:
{% extends 'base/base.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div class="card">
<form class="form-horizontal" action="" method="post">
{% csrf_token %}
<div class="card-body">
<div class="card-body">
<div class="form-horizontal">
{{ employAcademicFormSet.management_form }}
{% for form in employ_academic_forms %}
{% for field in form.visible_fields %}
<div class="form-group row">
<label class="col-md-3 col-form-label" for="text-input"><h6>{{ field.label_tag }}</h6></label>
<div class="col-md-9">{{ field }}</div>
</div>
{% endfor %}
{% endfor %}
</div>
</div>
</div>
<div class="card-footer">
<button class="btn btn-lg btn-primary" type="submit">Submit</button>
</div>
</form>
</div>
{% endblock %}
Does anyone know what is causing this? Please help me!!!
I think you might be using the wrong name when calling management_form.
Can you try replacing
{{ employAcademicFormSet.management_form }}
with
{{ employ_academic_forms.management_form }}
and see if that helps.

How can I give an error when someone edits there profile and changes the email to an email that already exists using django?

I want to give an error that an account with a email already exists, but it doesn't seem to work when a user edits there profile. Also, if the email isn't valid when submitting the form it it gives a value error: "The view accounts.views.edit_profile didn't return an HttpResponse object. It returned None instead."
Here is the code:
{% extends 'base.html' %}
{% block head %}
<link href="\static\accounts\css\forms.css" rel="stylesheet">
{% endblock %}
{% block body %}
<h3 style="text-align: center">Edit profile</h3>
<form id="login-form" method="post">
{% csrf_token %}
<input placeholder="Email" id="id_email" name="email"
type="text" class="form-control" value="{{ user.email}}">
<input placeholder="First name" id="id_first_name" name="first_name"
type="text" class="form-control" value="{{ user.first_name}} ">
<input placeholder="Last name" id="id_last_name" name="last_name"
type="text" class="form-control" value="{{ user.last_name}}">
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<p class=" label label-danger">
<div style="text-align: center">
{{ error }}
</div>
</p>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error }}</strong>
</div>
{% endfor %}
{% endif %}
<div style="text-align:center;">
<button type="submit" class="btn btn-outline-dark centerbutton">Save edits</button>
</div>
</form>
{% endblock %}
Also, here is the code I used to check if the email exists in the registration form, but it doesn't seem to work for the edit profile form:
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(username=username).exists():
raise forms.ValidationError(u'An account with this email address already exists')
return email
And my editprofileform:
class EditProfileForm(UserChangeForm):
class Meta:
model = User
fields = (
'email',
'first_name',
'last_name',
'password'
)
This is too large of a question to answer on here and I won't be posting any code for you. You will need to read some docs and work on it yourself.
Checking that email already exists... you will likely have to go to your database or for that. Enforcing that an email column be unique in your database is a good way to handle this. You can catch the database errors and handle them as you like.
As for the valid email validation, you will want to use Django's validators. One of the validators is specifically for checking valid email format.
https://docs.djangoproject.com/en/2.2/ref/validators/#emailvalidator

error is not displayed in the template

I have used django allauth for user registration and login. I have used the {{ form.has_errors }} in template to show an error but the error is not displayed in the template. What might be the reason for not showing an error in the template?
The code from allauth login.html(account/login.html)
{% block content %}
<div class="login-box">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-6 col-md-offset-3 login-area">
<span class="error">
{% if form.has_errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
</span>
<div class="panel panel-default">
<div class="panel-heading login-header">{% trans "Sign In" %}</div>
<div class="panel-body">
<form class="login" method="POST" action="{% url 'account_login' %}">
{% csrf_token %}
<div class="form-group form-group-lg">
<label for="emailAddress">Email address</label>
<input type="email" class="form-control" id="emailAddress id_login" name="login" placeholder="Email">
</div>
<div class="form-group form-group-lg">
<label for="password">Password</label>
<input type="password" class="form-control" id="password id_password" name="password" placeholder="Password">
</div>
<div class="form-group">
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
</div>
<button class="btn-block signin-btn btn-sm btn-primary pull-right m-t-n-xs" type="submit">{% trans "Sign In" %}</button>
</form>
</div>
<div class="panel-footer">
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
Try this one. Errors raised by the form which is not attached to field are stored in non_field_errors
{% if form.non_field_errors %}
<ul class='form-errors'>
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
or if you want to display in your way try this one
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
Seems to be a misunderstanding of has_error
his method returns a boolean designating whether a field has an error
with a specific error code. If code is None, it will return True if
the field contains any errors at all.
Coupled with the fact that you are rendering the form manually. Generally there are two types of form errors, non field errors and errors associated with each field (when their validation fails). The above method accepts a field name as a parameter and returns true if the field has failed validation.
You have several options, including continuing with your current approach but checking for form.errors instead of form.has_error or displaying the error with each field separately.

Styling forms using Django and Bootstrap

Okay, so I've created a simple purchase form which makes use of some custom form fields. I've rendered a simple form to test if it works properly, and it does, as shown below.
<form id="category_form" method="post" action="/purchase/">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="submit" value="Make purchase" />
</form>
Now, I wish to style it to Bootstrap 3. I've managed to style it with no problems using the django widget tweaks package. However, when I submit the form, I get this error 'NoneType' object has no attribute 'replace' I've tried it without the widget tweaks and I still get the same error.
Any ideas why this may be the case? The original form works fine unstyled, but as soon as I style it I get the above error. Now if my understanding is correct, Django takes one field and styles corresponding fields the same, but, some of my field types are different. i.e. dropdowns and text boxes, which can't be styled the same way. I'm not sure what the best way around this is.
views.py
def checkout(request):
if request.method == 'POST':
form = PurchaseForm(request.POST)
if form.is_valid():
form.save(commit=True)
return index(request) # Change this to point to the confirmation page
else:
print (form.errors)
else:
form = PurchaseForm()
return render(request, 'ticket/checkout.html', {'form': form})
checkout.html
<form class="form-horizontal" method="post" action="/cart/checkout/">
{% csrf_token %}
<fieldset>
<!-- Form Name -->
<legend>Card Details</legend>
<!-- Select Basic -->
<div class="form-group">
<label class="col-sm-3 control-label" for="card-type">{{ form.payment_type.help_text }}</label>
<div class="col-sm-9">
{{ form.payment_type|attr:"id:card-type"|attr:"name:card-type"|attr:"class:form-control" }}
{{ form.error }}
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-sm-3 control-label" for="card-name">{{ form.card_name.help_text }}</label>
<div class="col-sm-9">
{{ form.card_name|attr:"id:card-name"|attr:"name:card-name"|attr:"type:text"|attr:"placeholder:Card Holder's Name"|attr:"class:form-control input-md"|attr:"required:"}}
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-sm-3 control-label" for="card-number">{{ form.card_number.help_text }}</label>
<div class="col-sm-9">
{{ form.card_number|attr:"id:card-number"|attr:"name:card-number"|attr:"type:text"|attr:"placeholder:Credit / Debit card number"|attr:"class:form-control input-md"|attr:"required:"}}
</div>
</div>
<!-- Select Basic -->
<div class="form-group">
<label class="col-sm-3 control-label" for="expiry-date">{{ form.expiry_date.help_text }}</label>
<div class="col-sm-4">
{{ form.expiry_date|attr:"id:expiry-date"|attr:"name:expiry-date"|attr:"class:form-control col-sm-4" }}
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-sm-3 control-label" for="cvv-number">{{ form.security_code.help_text }}</label>
<div class="col-sm-9">
{{ form.security_code|attr:"id:cvv-number"|attr:"name:cvv-number"|attr:"type:text"|attr:"placeholder:Security Code"|attr:"class:form-control input-md"|attr:"required:"}}
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="date">{{ form.date.help_text }}</label>
<div class="col-sm-9">
{{ form.date|attr:"id:date"|attr:"name:date"|attr:"class:form-control input-md"|attr:"required:"}}
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="Purchase"></label>
<div class="col-md-8">
<button id="Purchase" name="Purchase" class="btn btn-success">Purchase</button>
<button id="Cancel" name="Cancel" class="btn btn-inverse">Cancel</button>
</div>
</div>
</fieldset>
I would suggest using the python package django-bootstrap3 to style your forms. It can be found at https://github.com/dyve/django-bootstrap3
Hope this helps!
I am not sure whether I understand your question correctly. However I noticed that 1. there seems no tag in your form.
2. maybe you can use plain html instead of other tag( {{ form.security_code|attr:"id:cvv-number"|attr:"name:cvv-number" ****}} ), such as
3. to validate form, you may try to write something like :
{% if form.password.errors %}
{% for error in form.password.errors %} {{ error}} {% endfor %} {% endif %}
Hope you figure out this problem as soon as possible.

Categories