In my registration
, I am enforcing that email-id
is unique. That is if a user exists with that email-id, I want to raise
a forms.ValidationError
.
Here is my form.py
:
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class MyRegistrationForm(UserCreationForm):
#define fields
email=forms.EmailField(required=True)
class Meta:
model=User
fields=('username','email','password1','password2')
def clean_email(self):
email = self.cleaned_data["email"]
try:
user = User.objects.get(email=email)
print user.email
print user.username
raise forms.ValidationError("This email address already exists. Did you forget your password?")
except User.DoesNotExist:
return email
def save(self, commit=True):
user = super(MyRegistrationForm, self).save(commit=False)
user.email=self.cleaned_data["email"]
if commit:
user.save()
return user
my view.py
:
def register_user(request):
if request.method=='POST':
form=MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Thank you for signing up")
return HttpResponseRedirect("/accounts/register_success")
args={}
args['form']=MyRegistrationForm()
return render(request,"register.html",args)
when I register
a user
with same email id, it does not throw validationError
. but simply return the register.html
but no duplicate user is added.
why is it not throwing validationError
?
I added a couple of print
statements in forms.py (above)
to print
the username
and email
that I get from User.object.get(email=email)
and it correctly prints the name
and email id
of previously registered user
. so the control proceeds till there but it is not throwing validationError
EDIT:
I also tried creating a brand new user
, but having passoword
fields Not match
.
still, I do not get any error
message. but it simply redirects to register.html
EDIT:
template/register.html
{% extends "base.html" %}
{% block content %}
<h2>Register</h2>
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="register"/>
</form>
{% endblock %}
In this template, error
gets displayed automatically right above the field
where the error occurs
. I don't have to do {{ form.email.error }}. However, I do not have a way to customize the error
. eg bold
or some css to them. Is that possible?
Django forms catch ValidationError
exception and adds error to form _errors
dict. This code from django BaseForm._clean_fields
method:
try:
# ...
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self._errors[name] = self.error_class(e.messages)
if name in self.cleaned_data:
del self.cleaned_data[name]
So, by raising ValidationError
exception you are telling django to add errors to cleaning field and make your form not valid.
You can access field error in template:
{{ form.field_name.errors }}
and iterate one field errors (django docs Customizing the form template):
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
and all fields errors (django docs Looping over the form’s fields):
{% for field in form %}
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% endfor %}
and display non field errors:
{{ form.non_field_errors }}
update: you should add else
block in view. Without else
you are always create new form:
def register_user(request):
if request.method=='POST':
form=MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Thank you for signing up")
return HttpResponseRedirect("/accounts/register_success")
else:
form = MyRegistrationForm()
args={}
args['form'] = form
return render(request,"register.html",args)