Django form validation, how to show messages on the fields? - django

I am building a register form, but I am having some trouble with its validation.
I would like to see the error message showing up at the field, but instead I am getting a error on the browser saying :
The User could not be created because the data didn't validate.
Request Method: POST
Request URL: http://127.0.0.1:8000/account/register/
Django Version: 1.9.8
Exception Type: ValueError
Exception Value:
The User could not be created because the data didn't validate.
Exception Location: C:\Python34\lib\site-packages\django\forms\models.py in save, line 446
This is my forms.py
class UserRegistrationForm(forms.ModelForm):
password = forms.CharField(label='Password', required=False ,widget=forms.PasswordInput)
password2 = forms.CharField(label='Repeat password', required=False ,widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username', 'first_name', 'email')
def clean_password2(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
#cd = self.cleaned_data
if not password2:
raise forms.ValidationError("Fill out the password2 .")
if password1 != password2:
raise forms.ValidationError("The two password fields didn't match.")
return password2
This is my view register
def register(request):
if request.method == 'POST':
user_form = UserRegistrationForm(request.POST)
if user_form.is_valid:
new_user = user_form.save(commit=False)
new_user.set_password(user_form.cleaned_data['password'])
new_user.save()
return render(request, 'account/register_done.html', {'new_user': new_user})
else:
print (user_form.errors)
else:
user_form = UserRegistrationForm()
return render(request, 'account/register.html', {'user_form': user_form})
my htmls - register.html
{% extends "account/base.html" %}
{% block title %}Create an account{% endblock %}
{% block content %}
<h1>Create an account</h1>
<p>Please, sign up using the following form:</p>
<form action="." method="post">
{{ user_form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Create my account"></p>
</form>
{% endblock %}
register_done.html
{% extends "account/base.html" %}
{% block title %}Welcome{% endblock %}
{% block content %}
<h1>Welcome {{ new_user.first_name }}!</h1>
<p>Your account has been successfully created. Now you can log in.</p>
{% endblock %}

Seems like you are not calling is_valid method, this may cause this issue:
if user_form.is_valid
Try to change above line to:
if user_form.is_valid()

Related

django's clean method doesn`t load form errors

i have a problem with Django clean method because clean method of form doesn`t load error in template. Could someone help me ?
template.html
{% extends "index.html" %}
{% block header %}
<div id="container-register">
<div class="logo-register">Zarejestruj się</div>
<div class="register-form">
<form method="post">
{% csrf_token %}
{% for field in form %}
{{ field }} {{ field.errors }} <br>
{% endfor %}
<input type="submit" value="Zarejestruj">
</form>
</div>
</div>
{% endblock %}
view.py
class AddUserView(View):
template_name = 'add_user.html'
def get(self,request):
return render(request, self.template_name,{
'form': AddUserForm()
})
def post(self,request):
form = AddUserForm(request.POST)
if form.is_valid():
User.objects.create_user(
username=form.cleaned_data.get('username'),
email=form.cleaned_data.get('email'),
password=form.cleaned_data.get('password'),
first_name=form.cleaned_data.get('first_name'),
last_name=form.cleaned_data.get('last_name')
)
return redirect('/login')
else:
return render(request, self.template_name, context={
'form': AddUserForm()
})
forms.py
class AddUserForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Nazwa użytkownika'}), max_length=100)
password = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Hasło'}), max_length=100)
password_repeat = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Powtórz hasło'}),
max_length=100)
first_name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Imię'}), max_length=100)
last_name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Nazwisko'}), max_length=100)
email = forms.EmailField(widget=forms.TextInput(attrs={'placeholder': 'Email'}), max_length=100)
def clean_username(self):
if User.objects.filter(username=self.cleaned_data.get('username')).exists():
raise ValidationError('Ten login jest już zajęty')
return self.cleaned_data.get('username')
def clean_password_repeat(self):
if self.cleaned_data.get('password') != self.cleaned_data.get('password_repeat'):
raise ValidationError('Podane hasła różnią się od siebie!')
return self.cleaned_data.get('password_repeat')
I checked the page source to see if the errors class was added in the html file.
In your post method, you create a new form in the template context instead of reuse the existing with data and errors :
return render(request, self.template_name, context={
'form': form
})

Problems with Django when trying to show error message when form insn't valid

Description
In my application i have a user registration form, but, when simulating not following the recommendations for form validation, i get an httpresponse error. But, what i'm trying to do is display an error message using the message framework from django
Code
My template
{% block body %}
{% if messages %}
{% for message in messages %}
<div class="text-center alert alert-{{ message.tags }}">
{{ message|safe }}
</div>
{% endfor %}
{% endif %}
{% load crispy_forms_tags %}
<form class = "" method="post" action="{% url 'registro' %}">
{% csrf_token %}
{{registro_form|crispy}}
<button class = "btn btn-primary" type="submit">Registrar</button>
</form>
{% endblock body %}
My Form
class NovoUsuarioForm(UserCreationForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email']
def save(self, commit = True):
user = super(NovoUsuarioForm, self).save(commit=False)
user.username = self.cleaned_data['first_name']
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if commit:
user.save()
return user
My View
class RegistroView(generic.View):
def get(self,request, *args, **kwargs):
return render(request, 'main/registro.html', {'registro_form': NovoUsuarioForm()})
def post(self,request, *args, **kwargs):
form = NovoUsuarioForm(request.POST)
if form.is_valid():
user = form.save()
login(request,user)
messages.success(request, "Registration successful." )
return HttpResponseRedirect(reverse('pesquisa'))
messages.error(request, "Unsuccessful registration. Invalid information.")
Other Info
When i go back to the form page, from the error page after the post method, i get the error message
Your view does not return an HTTP response if the form is NOT valid; the view does not have a return for that case, so it returns None.
This is the overview for your code:
class RegistroView(generic.View):
...
def post(self,request, *args, **kwargs):
...
if form.is_valid():
...
return HttpResponseRedirect(reverse('pesquisa'))
...
I suggest adding something like return HttpResponse(...) for the case when the form is not valid. The exact think you return depends on your use case.

Django Password Reset Confirm error (custom user model)

I am not that experienced writing Python/Back-end, but trying to improve. In development/localserver I am trying to create a password reset form... but I got the following error when accessing the link from the forgot password email - and before that the password was not saving:
get_context_data() missing 1 required positional argument: 'user'
forms.py (almost copy/paste from Django's form; minor changes)
class ResetPasswordForm(SetPasswordForm):
error_messages = {
'password_mismatch': static_textLanguage['page_user_passwordReset_alert_passwordNotMatch'],
'password_empty': static_textLanguage['global_alert_mandatoryField'],
'minimum_length': static_textLanguage['global_alert_minCharacters_password'],
}
new_password1 = forms.CharField(
required=False,
widget=forms.PasswordInput(attrs={
'id': 'page_userPasswordReset_content_form_input_passwordA',
'maxlength': '25',
'class': 'global_component_input_box'
}),
)
new_password2 = forms.CharField(
required = False,
widget=forms.PasswordInput(attrs={
'id': 'page_userPasswordReset_content_form_input_passwordB',
'maxlength': '25',
'class': 'global_component_input_box'
}),
)
def __init__(self, user, *args, **kwargs):
self.user = user
super(ResetPasswordForm, self).__init__(user, *args, **kwargs)
def clean_new_password1(self):
password1 = self.cleaned_data.get('new_password1')
if password1 == '' or password1 is None:
raise forms.ValidationError(self.error_messages['password_empty'], code='password_field_empty')
elif len(password1) < 8:
raise forms.ValidationError(self.error_messages['minimum_length'], code='password_too_short')
return password1
def clean_new_password2(self):
password1 = self.cleaned_data.get('new_password1')
password2 = self.cleaned_data.get('new_password2')
if password2 == '' or password2 is None:
raise forms.ValidationError(self.error_messages['password_empty'], code='password_field_empty')
if password1 and password2:
if password1 != password2:
raise ValidationError(self.error_messages['password_mismatch'], code='password_mismatch')
password_validation.validate_password(password2, self.user)
return password2
def save(self, commit=True):
password = self.cleaned_data["new_password1"]
self.user.set_password(password)
if commit:
self.user.save()
return self.user
views.py
class UserPasswordResetView(auth_views.PasswordResetConfirmView):
template_name = '../frontend/templates/frontend/templates.user/template.page_passwordReset.html'
form_class = ResetPasswordForm
post_reset_login = True
success_url = reverse_lazy('page_userLoginPrivate')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.user
return kwargs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.validlink:
context.update({
'validlink': True,
'form': self.form_class(),
'static_json_text': static_textLanguage,
'static_json_textGlobal': static_textGlobal
})
else:
context.update({
'validlink': False,
'form': None,
'title': _('Password reset unsuccessful'),
'static_json_text': static_textLanguage,
'static_json_textGlobal': static_textGlobal
})
return context
template.html (for purpose of this exercise .html was simplified)
<div class="wrapper_page_userPasswordReset">
{% if validlink %}
<form id="page_userPasswordReset_content_form" class="page_userPasswordReset_content_form" method="post" novalidate>
{% csrf_token %}
<div class="global_component_input_box_container">
{{ form.new_password1}}
</div>
<div id="page_userPasswordReset_input_passwordA_alert_errors" class="alert_message_input_danger_format">
{% if form.errors %}
{% for key, value in form.errors.items %}
{% if key == 'new_password1' %}
{{ value }}
{% endif %}
{% endfor %}
{% endif %}
</div>
<div class="global_component_input_box_container">
{{ form.new_password2}}
</div>
<div id="page_userPasswordReset_input_passwordB_alert_errors" class="alert_message_input_danger_format">
{% if form.errors %}
{% for key, value in form.errors.items %}
{% if key == 'new_password1' %}
{{ value }}
{% endif %}
{% endfor %}
{% endif %}
</div>
<button type="submit" id="page_userPasswordReset_content_form_button_submit" class="global_component_button button_background_green">{{ static_json_text.global_button_submit }}</button>
</form>
{% else %}
<button id="page_userPasswordReset_button_forgotPassword" class="global_component_button button_background_green">{{ static_json_text.page_user_passwordReset_notValidLink_button }}</button>
{% endif %}
</div>

Django not able to display form error

I am using Learning Website Development with Django book.
I have downloaded the source code from the fallowing path Source code in github. I am able to run the application in my windows machine.
However for some reason whenever login or registration from contains errors after submit, these errors are not shown in the html page.
Kindly let me know what is the issue. One obeseration what I saw in the browser console is
Following line of code displays error message
def register_page(request):
form = RegistrationForm(request.POST or None)
print request.method
if request.method == 'POST' and form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
password=form.cleaned_data['password1'],
email=form.cleaned_data['email']
)
return HttpResponseRedirect('/register/success/')
else:
form = RegistrationForm()
variables = RequestContext(request, {'form': form})
print variables
return render_to_response('registration/register.html', variables)
registration page html code:
{% extends "base.html" %}
{% block title %}User Registration{% endblock %}
{% block head %}User Registration{% endblock %}
{% block content %}
print "ddd"
{% if form.has_errors %}
<p>Your username and password didn't match.
Please try again.</p>
{% endif %}
<form method="post" action="">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="register" />
</form>
{% endblock %}
Login page code:
{% extends "base.html" %}
{% block title %}User Login{% endblock %}
{% block head %}User Login{% endblock %}
{% block content %}
{% if form.has_errors %}
<p>Your username and password didn't match.
Please try again.</p>
{% endif %}
<form method="post" action="">
{% csrf_token %}
<p><label for="id_username">Username:</label>
{{ form.username }}</p>
<p><label for="id_password">Password:</label>
{{ form.password }}</p>
<input type="submit" value="login" />
<input type="hidden" name="next" value="/" />
</form>
{% endblock %}
form.py
import re
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.models import User
from django import forms
class RegistrationForm(forms.Form):
print forms.Form;
username = forms.CharField(
label='Username',
max_length=30
)
email = forms.EmailField(
label='Email'
)
password1 = forms.CharField(
label='Password',
widget=forms.PasswordInput()
)
password2 = forms.CharField(
label='Password (Again)',
widget=forms.PasswordInput()
)
# password validation:
def cleaned_password2(self):
# all valid values are accessible trough self.clean_data
if 'password1' in self.cleaned_data:
password1 = self.cleaned_data['password1']
password2 = self.cleaned_data['password2']
if password1 == password2:
return password2
raise forms.ValidationError('Passwords do not match.')
# username validation
def cleaned_username(self):
username = self.cleaned_data['username']
if not re.search(r'^\w+$', username):
raise forms.ValidationError('Username can only contain alphanumeric characters and the underscore.')
try:
User.objects.get(username=username)
except ObjectDoesNotExist:
return username
raise forms.ValidationError('Username is already taken.')
class BookmarkSaveForm(forms.Form):
url = forms.URLField(
label='URL',
widget=forms.TextInput(attrs={'size': 64})
)
title = forms.CharField(
label='Title',
widget=forms.TextInput(attrs={'size': 64})
)
tags = forms.CharField(
label='Tags',
widget=forms.TextInput(attrs={'size': 64})
)
http://localhost:8000/static/style.css Failed to load resource: the server responded with a status of 404 (Not Found)
The code is simply wrong.
By combining the method == 'POST' and form.is_valid() into one check, they're ensuring that a new - empty - form is created if either of those things are false. What they should be doing is only creating an empty form if method does not equal "POST"; if the form is not valid, they need to return that invalid form to the template, as it contains the errors.
So you need to follow the normal pattern, with two separate if statements:
def register_page(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
password=form.cleaned_data['password1'],
email=form.cleaned_data['email']
)
return HttpResponseRedirect('/register/success/')
else:
form = RegistrationForm()
variables = RequestContext(request, {'form': form})
I Remenber i got the same problem, the thing i did is:
Use self.add_error to attach errors to a specific field in the form. Call add_error() instead of forms.ValidationError(), like this:
password validation:
def cleaned_password2(self):
# all valid values are accessible trough self.clean_data
if 'password1' in self.cleaned_data:
password1 = self.cleaned_data['password1']
password2 = self.cleaned_data['password2']
if password1 == password2:
return password2
msg = 'Passwords do not match.'
self.add_error('password1',msg)

Templates now showing any errors in Django

I have a form for registration. When I try to register, it does and everything is fine, just that, its now showing any Form Validation Errors in the template, when there should be.
forms.py:
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms
import re
from django.core.exceptions import ObjectDoesNotExist
class UserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'username',)
username = forms.EmailField(label='Email', max_length=250)
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.email = user.username
user.save()
return user
def clean_password2(self):
if 'password1' in self.cleaned_data:
password1 = self.cleaned_data['password1']
password2 = self.cleaned_data['password2']
if password1 == password2:
return password2
raise forms.ValidationError('Password do not match.')
def clean_username(self):
username = self.cleaned_data['username']
if not re.search(r'^\w[\w.]*#[\w.]+$', username):
raise forms.ValidationError('Please enter a valid email address.')
try:
User.objects.get(username=username)
except ObjectDoesNotExist:
return username
raise forms.ValidationError('Email address is already taken.')
views.py:
def register_user(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register_success')
else:
print form.is_valid()
print form.errors
args = {}
args.update(csrf(request))
args['form'] = UserCreationForm()
print args
return render_to_response('register.html', args)
register.html:
{% extends "base.html" %}
{% block content %}
<h1>Registration:</h1>
<form method="post" action=".">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Register" />
</form>
{% endblock %}
I even tried {% if form.errors %}:
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>{{form.errors }}</p>
{% endif %}
<h1>Registration:</h1>
<form method="post" action=".">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Register" />
</form>
{% endblock %}
But with no luck. I think I am missing something.
The reason is, if there are errors, you are overwriting it with form=UserCreationForm()
Basically, if if form.is_valid() is False, you need to send the form unaltered. By calling form=UserCreationForm after form.is_valid() you are overriding the errors
Try this:
def register_user(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register_success')
else:
print form.is_valid()
print form.errors
else:
form = UserCreationForm()
return render_to_response('register.html', {'form': form}, context_instance=RequestContext(request))