Django Forms: Cannot show Validation Error - python

I have a Django Form where I allow the user to submit a value only if his password matches a predefined password set by me : Pass_matcher
Validation works fine, such that if passwords match, value is entered and stored and if not, nothing happens.
However I want that if passwords do not match, I show a simple custom warning message. I looked at other SO questions such as here and here, but I can't seem to get it right.
Note: If the user enters the correct password I do not want to redirect to another page.
forms.py
from django import forms
class TactForm(forms.Form):
password = forms.CharField(widget=forms.PasswordInput(
attrs = {
'class' : 'form-control mb-2 mr-sm-2 mb-sm-0',
'placeholder' : 'Enter Password:',
'id' : 'inlineFormInput',
'required' : 'true'
}
), required = True, label='Tact Password', max_length=100)
tacttime = forms.CharField(widget=forms.TextInput(
attrs = {
'class': 'form-control mb-2 mr-sm-2 mb-sm-0',
'placeholder': 'Enter Tact Time:',
'id' : 'inlineFormInput2'
}
),label='Tact Time', max_length=100)
def clean(self):
cleaned_data = super(TactForm,self).clean()
password = cleaned_data.get('password')
current_tact = cleaned_data.get('tacttime')
if password != 'Pass_matcher':
print('incorrect') #this prints to console if incorrect
raise forms.ValidationError('Incorrect Password') # this does not work
else:
print('correct') #this prints to console if correct
return cleaned_data
views.py
def details(request):
form = TactForm(request.POST or None)
if request.method == 'POST':
form = TactForm(request.POST)
if form.is_valid():
print('here1')
current_tact = form.cleaned_data['tacttime']
password = form.cleaned_data['password']
else:
form = TactForm()
return render(request, 'linedetails/index.html',{'form':form})
template
<div class="user_in" style="text-align:center;">
<form class="form-inline" method="POST" action="{% u$
{% csrf_token %}
{{ form.password }}
{{ form.tacttime }}
<br>
<button type="submit" class="btn btn-outline>
</form>
</div>
The below code is experimental
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
I cannot understand why the raise forms.ValidationError('Incorrect Password')
is not shown if the statement above it is correctly printed to terminal.
I am thinking that I have something missing in else statement of the views.py script.
Thanks for any suggestions.

You redefined form instance if form is not valid. just remove else block to fix it:
def details(request):
form = TactForm(request.POST or None)
if request.method == 'POST':
form = TactForm(request.POST)
if form.is_valid():
print('here1')
current_tact = form.cleaned_data['tacttime']
password = form.cleaned_data['password']
return render(request, 'linedetails/index.html',{'form':form})
Also you actually dont need if request.method == 'POST' validation since form will be populated with post data automatically here form = TactForm(request.POST or None). So you can simply rewrite your view to this:
def details(request):
form = TactForm(request.POST or None)
if form.is_valid():
print('here1')
current_tact = form.cleaned_data['tacttime']
password = form.cleaned_data['password']
return render(request, 'linedetails/index.html',{'form':form})

Related

Django Model Form not showing errors after validation in clean()

Can you help me out with this. I hava a model form and I need to raise an error after validate two datetime objects in the clean method of the model form. This is what I have.
Forms
class HorariosDisponibles(forms.ModelForm):
tutor = forms.ModelChoiceField(queryset=Tutor.objects.all(),widget=forms.Select(attrs= {'class': 'input is-small is-rounded ' }),label='TUTOR',)
dia_hor_inicio =forms.DateTimeField(widget=forms.DateTimeInput(attrs= {'class': 'input is-small is-rounded ',}),label='Horario de Inicio', initial=datetime.date.today )
dia_hor_fin= forms.DateTimeField(widget=forms.DateTimeInput(attrs= {'class': 'input is-small is-rounded ' }),label='Horario de FinalizaciĆ³n', initial=datetime.date.today)
class Meta:
model = horarios_disp
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["dia_hor_inicio"].widget = DateTimeInput()
self.fields["dia_hor_inicio"].input_formats = ["%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M"]
self.fields["dia_hor_fin"].widget = DateTimeInput()
self.fields["dia_hor_fin"].input_formats = ["%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M"]
def clean(self):
cleaned_data = super(HorariosDisponibles, self).clean()
tutor = cleaned_data.get("tutor")
dia_hor_inicio = cleaned_data.get("dia_hor_inicio")
dia_hor_fin = cleaned_data.get("dia_hor_fin")
if dia_hor_inicio and dia_hor_fin:
if dia_hor_inicio.day != dia_hor_fin.day :
msg = 'Las fechas no pueden ser distintas'
self.add_error("dia_hor_inicio", msg)
raise forms.ValidationError("Las fechas no pueden ser distintas")
#NEITHER OF THIS APPROACHES WORKED
return cleaned_data
VIEWS
#login_required
def horario_tutor(request):
context = {
}
if request.method == 'POST':
print(request.POST)
form = HorariosDisponibles(request.POST)
if form.is_valid():
tutor = form.cleaned_data['tutor']
print("adentro")
dia_hor_inicio = form.cleaned_data['dia_hor_inicio']
dia_hor_fin = form.cleaned_data['dia_hor_fin']
tutor_horario = horarios_disp(
tutor=tutor, dia_hor_inicio=dia_hor_inicio, dia_hor_fin=dia_hor_fin)
tutor_horario.save()
context = {
'form': form
}
return redirect("home")
return render(request,"horarios_disponibles.html", context)
else:
form = HorariosDisponibles()
context['form'] = form
return render(request, "horarios_disponibles.html", context)
TEMPLATES
{% extends 'base.html' %}
{% block body %}
<section class="section">
<div class="columns is-vcentered">
<div class="column is-centered is-4 is-offset-2">
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="field">
{% for error in field.errors %}
<p class="help is-danger">{{ error }}</p>
{% endfor %}
<label for="{{field.id_for_label}}" class="label">{{ field.label }}</label>
{{ field }}
{% for non_field_error in form.non_field_errors %}
<p class="help is-danger">{{ non_field_error }}</p>
{% endfor %}
{% if field.help_text %}
<p class="help is-danger">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<p class="control">
<button class="button is-link" type="submit">
Enviar
</button>
</p>
</form>
</section>
It validates if I put two different dates in the form, but it doesn't enter to is_valid() (because ther form is not valid). Render just the button of the template.
Try this:
if form.is_valid():
tutor = form.cleaned_data['tutor']
dia_hor_inicio = form.cleaned_data['dia_hor_inicio']
dia_hor_fin = form.cleaned_data['dia_hor_fin']
tutor_horario = horarios_disp(
tutor=tutor, dia_hor_inicio=dia_hor_inicio, dia_hor_fin=dia_hor_fin
)
tutor_horario.save()
context = {'form': form}
return redirect("home")
else:
context = {'error': 'whatever error you want to show here'}
return render(request, "horarios_disponibles.html", context)
# and probably some extra handling at the end in case there are errors
As a matter of fact, you won't need to declare the context = {} at the beginning of your code before if request.method == 'POST' because you're going to declare one on in the if-else statement anyways.

Showing error messages in template in DefaultUserCreationForm - django

I am having a problem in displaying an error message in the HTML page. I am using Django's default UserCreationForm for signup page. It has two password fields - one original and one for confirmation. When the user enters different passwords, I am getting at /signup/ whereas I want the error message to be displayed in the HTML page saying that the passwords didn't match. I have gone through the docs and I have added some related lines in my code, I don't know where I'm going wrong.
Here is my views.py:
def adduser(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
print(request.POST)
if(form.is_valid):
try:
user = employees.objects.get(emp_id=request.POST['username'] )
except employees.DoesNotExist:
user = None
print(user)
if( user != None ):
if request.POST['username'] in employees.objects.values_list('manager_id__emp_id',flat=True):
g = Group.objects.get(name='Managers')
newuser = form.save()
newuser.groups.add(g)
else:
g = Group.objects.get(name='Employees')
newuser = form.save()
newuser.groups.add(g)
return render(request,'login.html',{'form': form})
else:
form = UserCreationForm()
return render(request,'signup.html', {'form': form, 'msg': 'Enter valid employee id'})
else:
form = UserCreationForm()
return render(request,'signup.html', {'form': form})
and here is my signup.html:
<body>
<div class="container">
<div class="page-header">
<h1>Sign-up Here</h1>
</div>
{% block body %}
<form method="post">
{% csrf_token %}
<font color="orange" size="5px"><p> * Enter your Employee id, as username * </p></font>
{{ form.as_p }}
<font color="red"> {{ msg }} </font><br>
<font color="red"> {{ form.password1.errors }} </font><br>
<font color="red"> {{ form.password2.errors }} </font><br>
<br>
<button class="btn btn-success" type="submit"> Go! </button>
</form>
{% endblock %}
</div>
</body>
The problem is in this line :
if(form.is_valid):
This is not the correct way of testing form validation,
instead use:
if form.is_valid():
Also you dont need to declare form multiple times,it can be done single time.
Like this :
def adduser(request):
form = UserCreationForm(request.POST or None)
if request.method == 'POST':
print(request.POST)
if form.is_valid():
try:
user = employees.objects.get(emp_id=request.POST['username'] )
except employees.DoesNotExist:
user = None
print(user)
if( user != None ):
if request.POST['username'] in employees.objects.values_list('manager_id__emp_id',flat=True):
g = Group.objects.get(name='Managers')
newuser = form.save()
newuser.groups.add(g)
else:
g = Group.objects.get(name='Employees')
newuser = form.save()
newuser.groups.add(g)
return render(request,'login.html',{'form': form})
else:
form = UserCreationForm()
return render(request,'signup.html', {'form': form, 'msg': 'Enter valid employee id'})
return render(request,'signup.html', {'form': form})
And there can be diffrenmt type of erros, field and non_field_errors, so use someting like this :
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}

'ErrorDict' object has no attribute 'status_code' while validating form

I have models.py and forms.py, views.py and as bellow . I want only alpha numeric inputs . after submitting the form, i am getting the error :'ErrorDict' object has no attribute 'status_code'
Kindly suggest .
from django.core.validators import RegexValidator
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', 'Only alphanumeric characters are allowed.')
class News_Post(models.Model):
Country=models.CharField(max_length=20, validators=[alphanumeric])
State=models.CharField(max_length=20, validators=[alphanumeric])
District=models.CharField(max_length=20, validators=[alphanumeric])
Area=models.CharField(max_length=20, validators=[alphanumeric])
Photo_link=models.CharField(max_length=50,blank=True)
News_Title=models.CharField(max_length=200, validators=[alphanumeric])
News=models.TextField(validators=[alphanumeric])
created_date=models.DateTimeField(auto_now_add=True,)
author = models.CharField(max_length=20)
def __str__(self):
return self.News_Title
forms.py:
from django import forms
from django.forms import ModelForm
class NewsForm(forms.ModelForm):
Country=forms.CharField(max_length=20, required=False, help_text='Optional.')
State=forms.CharField(max_length=20, required=False, help_text='Optional.')
District=forms.CharField(max_length=20, required=False, help_text='Optional.')
Area=forms.CharField(max_length=20, required=False, help_text='Optional.')
Photo_link=forms.CharField(max_length=50, required=False, help_text='Optional.')
News_Title=forms.CharField(max_length=200, required=True, help_text='Required')
News=forms.CharField(widget=forms.Textarea)
class Meta:
model = News_Post
fields = ('Country','State','District','Area','Photo_link','News_Title', 'News', )
exclude = ["author"]
Views.py:
.
def new_submit(request):
if request.method == 'POST':
form = NewsForm(request.POST)
if form.is_valid():
c=form.save(commit=False)
c.author = request.user
c.save()
return redirect(my_submitted_news )
else:
return form.errors
else:
form = NewsForm()
return render(request,'new_submit.html', {'form': form})
new_submit.html:
{% block content %}
{% if form.errors %}
<p style="color: red"> Please try again.</p>
{% endif %}
<form method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit">Submit News</button>
{% endblock %}
Edit your view,
def new_submit(request):
if request.method == 'POST':
form = NewsForm(request.POST)
if form.is_valid():
c=form.save(commit=False)
c.author = request.user
c.save()
return redirect('your_url_name' )
else:
return render(request, 'template_name', dict(form, form))
else:
form = NewsForm()
return render(request,'new_submit.html', {'form': form})
When the form is not valid, your else statement returns form.errors directly. That is not a valid thing to return from a view; views always need to return an HTTP response.
You should remove that first else statement, and let execution fall through to the final line so that your template is rendered with the invalid form. You should also modify the template so that it actually outputs the contents of form.errors.

User got saved in django regardless of other two forms with it are valid or not

UserForm got saved no matter if other two forms (StudentOrFacultyForm and UserIdForm) are valid or not. User should not be created if other two forms are invalid. Please help!
models.py
class StudentOrFaculty(models.Model):
STUDENT = 'S'
FACULTY = 'F'
PROFILE_CHOICES = (
(STUDENT, 'Student'),
(FACULTY, 'Faculty'),
)
# Links to a User model instance
user = models.OneToOneField(User, related_name='fors')
# The Additional attributes
st_or_faculty = models.CharField(max_length=1, choices=PROFILE_CHOICES)
def __str__(self):
if(self.st_or_faculty == 'S'):
fullname = 'Student'
elif(self.st_or_faculty == 'F'):
fullname = 'Faculty'
else:
fullname = 'Unknown'
return str(self.user) + " is " + fullname
class UserActivation(models.Model):
user = models.OneToOneField(User)
activation_key = models.CharField(max_length=255, blank=True)
key_expires = models.DateTimeField(default=(timezone.now() + timedelta(days=1)))
def __str__(self):
return self.user.username
class Meta:
verbose_name_plural=u'Activation'
class UserIdCard(models.Model):
user = models.OneToOneField(User)
id_card = models.ImageField(upload_to='id_cards')
forms.py
FORS_CHOICES = (('F','Faculty'),('S','Student'))
class UserForm(forms.ModelForm):
first_name = forms.CharField(help_text="Frist Name")
last_name = forms.CharField(help_text="Last Name")
username = forms.CharField(help_text="Username")
email = forms.CharField(help_text="Email")
password = forms.CharField(widget=forms.PasswordInput(),
help_text="Password")
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'email',
'password')
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).count():
raise forms.ValidationError(u'this Email is already registered.')
return email
class StudentOrFacultyForm(forms.ModelForm):
"""
Studentorfaculty option
"""
st_or_faculty = forms.ChoiceField(
label="Student Or Faculty",
required=True,
choices=FORS_CHOICES,
widget=forms.RadioSelect,
help_text="Student Or Faculty")
class Meta:
model = StudentOrFaculty
fields = ('st_or_faculty',)
class UserIdCardForm(forms.ModelForm):
id_card = forms.ImageField(label="College Id Card")
class Meta:
model = UserIdCard
fields = ('id_card',)
def clean_id_card(self):
image = self.cleaned_data.get('id_card',False)
if image:
if hasattr(image,'_size'):
if image._size > 4*1024*1024:
raise ValidationError("Image file too large (should be < 4mb )")
return image
else:
raise ValidationError("Couldn't read uploaded image")
views.py
def user_signup(request):
# get the request's context
context = RequestContext(request)
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('notices:index'))
# A boolean value for telling the template whether the signup was successfull
# Set to flase initially. Code changes value to True when registration
#successfull
registered = False
# If it's a HTTP POST, we're interested in processing form data
if request.method == 'POST':
# Attempt to grab information
# We make use of UserForrm and UserProfileForm
user_form = UserForm(data=request.POST)
student_or_faculty_form = StudentOrFacultyForm(data=request.POST)
user_id_card_form = UserIdCardForm(data=request.POST, files=request.FILES)
# If the two foms are valid
if user_form.is_valid() and student_or_faculty_form.is_valid() and\
user_id_card_form.is_valid():
# Save the user's form data to the database.
user = user_form.save()
# Now we hash the password with set_password method.
# One hashed, we can update the user object.
user.set_password(user.password)
user.is_active = False
user.save()
uid = user_id_card_form.save(commit=False)
uid.user = user
uid.save()
fors = student_or_faculty_form.save(commit=False)
fors.user = user
fors.save()
username = user_form.cleaned_data['username']
email = user_form.cleaned_data['email']
tmp = random.random()
tmp = str(tmp)
tmp = tmp.encode('utf-8')
salt = hashlib.sha1(tmp).hexdigest()[:5]
salt = salt.encode('utf-8')
email_en = email.encode('utf-8')
activation_key = hashlib.sha1(salt+email_en).hexdigest()
key_expires = datetime.datetime.today() + datetime.timedelta(2)
email = user_form.cleaned_data['email']
#Get user by username
user=User.objects.get(username=username)
new_profile = UserActivation(user=user, activation_key=activation_key,
key_expires=key_expires)
new_profile.save()
# Send email with activation key
email_subject = 'Account confirmation'
email_body = "Hey %s, thanks for signing up. To activate your account, click this link within \
48hours http://www.socialboard.in/accounts/confirm/%s" % (username, activation_key)
send_mail(email_subject, email_body, 'support#socialboard.in',
[email], fail_silently=False)
# log in the user
user_name = request.POST['username']
'''new_user = authenticate(username=request.POST['username'],
password=request.POST['password'])
login(request, new_user)'''
# Update the variable to tell the registration was successful
registered = True
return HttpResponseRedirect(reverse('accounts:aftersignup', kwargs={'user_name':user_name}))
# Invalid forms
# Print problems to the terminal.
# they will also be show to the user
else:
print( user_form.errors, student_or_faculty_form.errors, user_id_card_form.errors )
# Not a HTTP POST, so we render our form using two instance
# These forms will be blank, ready for the user input.
else:
user_form = UserForm()
student_or_faculty_form = StudentOrFacultyForm()
user_id_card_form = UserIdCardForm()
# Render the template depending on the context.
return render_to_response(
'accounts/signup.html',
{ 'user_form': user_form, 'student_or_faculty_form': student_or_faculty_form,
'user_id_card_form': user_id_card_form,
'registered': registered},
context)
signup.html
<form class="form-horizontal" role="form" id="user_form" method="post" action="{% url 'accounts:signup' %}"
enctype="multipart/form-data">
{% csrf_token %}
{% for field in user_form.visible_fields %}
<div class="form-group has-feedback">
<div class="col-sm-12"><input type="{{ field.field.widget.input_type }}" class="form-control" name="{{ field.name }}" placeholder="{{ field.label}}" value="{% if field.value %}{{field.value}}{% endif %}"></div>
{% if field.errors %} <div class="col-sm-10 text-danger"> {{ field.errors }} </div> {% endif %}
</div>
{% endfor %}
{% for fieldi in student_or_faculty_form.visible_fields %}
<div class="from-group has-feedback">
<!--<label class="col-sm-2 control-label">I am </label>-->
{% for value,text in fieldi.field.choices %}
<label class="radio-inline">
<input type="radio" name="{{ fieldi.name }}" id="" value="{{ value }}"><b> {{ text }}</b>
</label>
{% endfor %}
{% if fieldi.errors %} <div class="col-sm-10 text-danger "> {{ fieldi.errors }} </div> {% endif %}
</div>
{% endfor %}
<br>
{% for field in user_id_card_form.visible_fields %}
<div class="form-group has-feedback">
<div class="col-sm-12"><b>{{field.field.label}} :</b></div>
<div class="col-sm-12"><input type="{{ field.field.widget.input_type }}" class="form-control" name="{{ field.name }}"
placeholder="{{ field.label}}" value="{% if field.value %}{{field.value}}{% endif %}"></div>
{% if field.errors %} <div class="col-sm-10 text-danger"> {{ field.errors }} </div> {% endif %}
</div>
{% endfor %}
<!-- Provide a button to click to submit the form -->
<div class="form-group">
<div class="col-sm-offset-0 col-sm-10">
<button type="submit" class="btn btn-warning"><b>Sign Up</b></button><br><br>
<div>or have an account? <span class="btn btn-xs btn-default">Log In</span></div>
</div>
</div>
</form>

Showing a empty GET form without raising any error on Django

I'm trying to set an home page one my project that show a search form (with GET method).
The problem is that it raises an error at the moment I load the very page since the default request method is GET. Of course I can change the form's method to POST but that would not be the correct way, so I was wondering if there was any condition that I can set to avoid this issue and still be able to check any errors.
I'm working on Django 1.5 and Python 2.7
This if the form class:
class Search(forms.Form):
middleschool = 'MS'
highschool = 'HS'
university = 'U'
blank = '-'
school_choices = ((middleschool, 'Middle School'),
(highschool, 'High school'),
(university, 'University'),
(blank, 'Not defined'),)
title = forms.CharField(label='Keyworld')
subject = forms.ModelChoiceField(queryset=Subject.objects.order_by('?'),
required=False, label='Whitch subject you want to search?')
school = forms.ChoiceField(choices = school_choices, required=False,
label='What level of material are you searching?')
price = forms.BooleanField(required=False)
This is the relative view:
def home(request):
if request.method == 'GET':
form = Search(request.GET)
if form.is_valid():
cd = form.cleaned_data
ftitle = cd['title']
fsubject = cd['subject']
fschool = cd['school']
fprice = cd['price']
if fprice:
forms = File.objects.filter(name__contains='ftitle', subject='fsubject', school='fschool', price = '0,0')
return render(request, 'search.html', {'form': form})
else:
forms = File.objects.filter(name__contains='ftitle', subject='fsubject', school='fschool')
return render(request, 'search.html', {'form': form})
else:
form = Search()
return render(request, 'home.html', {'form': form})
This is the HTML:
{% block content %}
<hr>
<div id='search'>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="/search/" method="get">
<div class="field">{{ form.title.errors }}<label for="keyworld">Keyworld:</label>{{ form.title }}</div>
<div class="field"><label for="subject">Subject:</label>{{ form.subject }}</div>
<div class="field"><label for="school">Level:</label>{{ form.school }}</div>
<div class="field"><label for="price">Price yes or no:</label>{{ form.price }}</div>
<input type="submit" value="Search">
<input type="reset" value="Reset">
</form>
</div>
<hr>
{% endblock %}
You simply have to add or None, like this:
form = SearchForm(request.GET or None)
Rather than checking the request method, you could check whether request.GET is empty:
if request.GET:
form = SearchForm(request.GET)

Categories

Resources