Django: errors not being shown when form is submitted - django

clean is not showing errors on my login form regardless of what my input is and regardless of what method of displaying errors I try in clean.
In my CustomUserCreationForm error displaying works perfectly. The only difference between the two is login extends forms.Form while Custom extends UserCreationForm
Also I'm using django-crispy-forms to render my forms
class LoginForm(forms.Form):
username = forms.CharField(label=('UserName'),
widget = forms.TextInput(attrs={'placeholder': _('Username')})
)
password = forms.CharField(label=('Password'),
widget=forms.PasswordInput(attrs={'placeholder' : _('Password') }),
)
def helper(self):
helper = FormHelper()
helper.form_id = "Login"
helper.form_method = "POST"
helper.layout = Layout(Div(
Field('username', css_class='input-box-rounded'),
Field('password', css_class='input-box-rounded'),
Submit('Login', 'Login', css_class='col-md-6 col-md-offset-3 rounded'),
css_class='col-md-4 col-md-offset-4 centered-div'))
return helper
def clean(self):
cleaned_data = super(LoginForm, self).clean()
if 'username' not in cleaned_data:
msg = _("Please enter a username")
self._errors['username'] = self.error_class([msg])
if 'password' not in cleaned_data:
msg = _("Please enter a password")
raise forms.ValidationError(msg)
u =authenticate(username = cleaned_data['username'], password = cleaned_data['password'])
if u == None:
msg = _("Username or Password is incorrect")
self.add_error('username', msg)
return cleaned_data

Can you post your view and template code? Without seeing either of those, I assume either your template needs to display the errors or your view is not handling the form, though I haven't used Django Crispy Forms.
{{ form.non_field_errors }}
{{ form.username.errors }}
FYI, the preferred way to handle error checking is to create a clean function for each field and have it raise a ValidationError when there is a problem. This will then be a field error (second line above).
def clean_password(self):
data = self.cleaned_data.get('password')
if not data:
raise ValidationError(_("Please enter a password"))
Also, since you're just checking that a field is there, so you could set required=True for each required field and skip the manual validation.
class LoginForm(forms.Form):
username = forms.CharField(label=('UserName'), required=True,
widget = forms.TextInput(attrs={'placeholder': _('Username')})
)
password = forms.CharField(label=('Password'), required=True,
widget=forms.PasswordInput(attrs={'placeholder' : _('Password') }),
)
See the documentation for more info: https://docs.djangoproject.com/en/dev/topics/forms/#customizing-the-form-template

Related

Django ValueError The given username must be set from form self on form overridden save method

I´m in a django simple 3.2.9 project. When i try to override my form save method, y get next error:
ValueError The given username must be set from form self
It´s quite annoying, cause if I don´t override and call the save functionality from the view, it works just fine, but if I override method, it seems it can´t get self attributes from form, though it can do that on other validation methods within the class.
This, my RegisterForm class.
class RegisterForm(forms.Form):
username=forms.CharField(
required=True,
min_length=4,max_length=50,
widget=TextInput(attrs={
'class':'form-control'
})
)
email=forms.EmailField(
required=True,
min_length=4,max_length=50,
widget=TextInput(attrs={
'class':'form-control'
})
)
pwd=forms.CharField(
required=True,
min_length=4,max_length=50,
widget=PasswordInput(attrs={
'class':'form-control'
})
)
pwdr=forms.CharField(
required=True,
min_length=4,max_length=50,
widget=PasswordInput(attrs={
'class':'form-control'
})
)
def clean_username(self):
username=self.cleaned_data.get('username')
if User.objects.filter(username=username).exists():
raise forms.ValidationError('Ese nombre de usuario ya se encuentra en uso')
return username
def clean_email(self):
email=self.cleaned_data.get('email')
if User.objects.filter(email=email).exists():
raise forms.ValidationError('Ese email ya se encuentra en uso')
return email
def clean(self):
cleaned_data=super().clean()
if cleaned_data.get('pwd')!= cleaned_data.get('pwdr'):
self.add_error('pwdr','Las contraseñas no coinciden')
return redirect('register')
return redirect('home')
def save(self):
username=self.cleaned_data.get('username')
email=self.cleaned_data.get('email')
pwd=self.cleaned_data.get('pwd')
return User.objects.create_user(
username,
email,
pwd
)
This self contents from print(self) inside save method
label for="id_username">Username:<input
type="text" name="username" value="vidalon" class="form-control"
maxlength="50" minlength="4" required id="id_username">
Email: Pwd: Pwdr:
---UPDATED---
I got this from django docs
where we can read the following:
Note that Form.add_error() automatically removes the relevant field
from cleaned_data.
So basically i had a validation on two password fields and a form class with a clean method to validate these two related fields like this:
def clean(self):
cleaned_data=super().clean()
if cleaned_data.get('pwd')!= cleaned_data.get('pwdr'):
self.add_error('pwdr','Passwords doesn´t match')
return redirect('register')
return redirect('home')
So i guess question is solved, now it makes sense keep coding!
Thanks for the interest
I got this from django docs
where we can read the following:
Note that Form.add_error() automatically removes the relevant field from cleaned_data.

Django - This is field is required error

I am new to Django and trying to save some data from the form to the model. I want to insert into two models which have a foreign key constraint relationship (namely Idea and IdeaUpvotes) i.e. from a html template to a view.
My submit code is:
def submitNewIdea(request):
#get the context from the request
context = RequestContext(request)
print(context)
#A HTTP POST?
if request.method == 'POST':
form = submitNewIdeaForm(request.POST)
# Have we been provided with a valid form?
if form.is_valid():
# Save the new Idea to the Idea model
print(request.POST.get("IdeaCategory"))
print(request.POST.get("IdeaSubCategory"))
i = Idea( idea_heading = form["idea_heading"].value()
,idea_description = form["idea_description"].value()
,idea_created_by = form["idea_created_by"].value()
,idea_votes = form["idea_votes"].value()
,idea_category = request.POST.get("IdeaCategory") #value from dropdown
,idea_sub_category = request.POST.get("IdeaSubCategory") #value from dropdown
)
i.save()
# get the just saved id
print(Idea.objects.get(pk = i.id))
iu = IdeaUpvotes(idea_id = Idea.objects.get(pk = i.id)
,upvoted_by = form["upvoted_by"].value()
,upvoted_date = timezone.now() )
iu.save()
form.save(commit = True)
# Now call the index() view.
# The user will be shown the homepage.
return index(request)
else:
# The supplied form contained errors - just print them to the terminal.
print (form.errors)
else:
# If the request was not a POST, display the form to enter details.
form = submitNewIdeaForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request,'Ideas/Index.html',{'form' :form})
form.py --->
class submitNewIdeaForm(forms.ModelForm):
idea_heading = forms.CharField(label = "idea_heading",max_length =1000,help_text= "Please enter the idea heading.")
idea_description= forms.CharField(label = "idea_description",max_length =1000,help_text= "Please enter the idea description.",widget=forms.Textarea)
idea_created_by=forms.CharField(max_length =200, widget = forms.HiddenInput(), initial='wattamw')
idea_votes = forms.IntegerField(widget=forms.HiddenInput(), initial=1)
upvoted_by=forms.CharField(max_length =200, widget = forms.HiddenInput(), initial='abcde')
"""
#commented code
#idea_category_name = forms.CharField(label = "idea_category_name",max_length =250,help_text= "Please select an Idea Category.")
#idea_sub_category = forms.CharField(label = "idea_sub_category",max_length =250,help_text= "Please select an Idea Sub Category.")
idea_category_name = forms.ModelChoiceField(
queryset = IdeaCategory.objects.all(),
widget=autocomplete.ModelSelect2(url='category-autocomplete'))
idea_sub_category = forms.ModelChoiceField(
queryset = IdeaSubCategory.objects.all(),
widget = autocomplete.ModelSelect2(
url='subcategory-autocomplete',
forward = (forward.Field('idea_category_name','id'),)))
"""
class Meta:
model = Idea
fields = ('idea_heading','idea_description','idea_created_by','idea_votes','idea_category_name','idea_sub_category')
class Meta:
model = IdeaUpvotes
fields = ('upvoted_by',)
def __init__(self,*args,**kwargs):
super(submitNewIdeaForm,self).__init__(*args,**kwargs)
self.fields['idea_category_name'] = forms.ModelChoiceField(
queryset = IdeaCategory.objects.all(),
widget=autocomplete.ModelSelect2(url='category-autocomplete'))
self.fields['idea_sub_category'] = forms.ModelChoiceField(
queryset = IdeaSubCategory.objects.all(),
widget = autocomplete.ModelSelect2(
url='subcategory-autocomplete',
forward = (forward.Field('idea_category_name','id'),)))
I am able to print the values and see that they are passed,but I still get the following error :
Error Description
I have removed any foreign key references to the table, the fields are simple character fields.
Please help me out.
Thanks.
In the first place, your form validation is failing. It seems to me that your form template may be wrong.
The second thing is that you don't use Django forms properly. All you need to do to achieve the functionality you are looking for is to use ModelForm and let the form's save method to create the object for you. All you need to do is:
Associate your SubmitNewIdeaForm with the Idea model:
# forms.py
class SubmitNewIdeaForm(ModelForm):
class Meta:
model = Idea
fields = (
'idea_heading',
'idea_description',
'idea_created_by',
'idea_votes',
'idea_category',
'idea_sub_category'
)
Render the form
#form_template.html
<form action="{% url 'your_url' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
Finally jsut check if the form is valid and call form.save() like so:
def submitNewIdea(request):
if form.is_valid():
form.save()
That's it! I hope that I helped you.
Cheers!
Finished = models.IntegerField('Finished percentage', error_messages={'required':''})
Worked for me.

AttributeError: 'AcceptInvite' object has no attribute 'email'

Im doing some unit testing in my Django project, and am getting error
"AttributeError: 'SignUp' object has no attribute 'email'"
when I run this test.
def test_signup(self):
response = self.c.post('/accounts/signup/', {'email': 'test#test.com', 'password': 'test123', 'password_conf': 'test123',
'org_name': 'test org', 'org_username': 'test org username', 'invite': '4013'})
code = response.status_code
self.assertTrue(code == 200)
The view this is testing simply takes a signup form, and creates a new account with it.
def signup(request):
# """Register a new account with a new org."""
if request.method == "POST":
form = SignUp(request.POST)
if not form.email or not form.password:
raise Exception("Email and Password are required")
if form.password != form.password_conf:
raise Exception("Password does not match confirmation")
if not form.org_name or not form.org_username:
raise Exception('Organization name and username are required')
if not form.invite:
raise Exception('Invitation code is required')
if form.is_valid():
cleaned_data = form.cleaned_data
email = cleaned_data['email']
password = cleaned_data['password']
org_name = cleaned_data['org_name']
org_username = cleaned_data['org_username']
invite_token = cleaned_data['invite']
invitation = OrgInvite.objects.get(token=invite_token)
if invitation.used:
raise Exception("invitation code is invalid")
account = Account(email=email, password=password)
account.save()
org = Org(org_name=org_name, org_username=org_username)
org.save()
invitation.used = False
invitation.save()
login(request)
# Send Email
md = mandrill.Mandrill(settings.MANDRILL_API_KEY)
t = invite_token.replace(' ', '+')
url = "https://www.humanlink.co/verify/{}".format(t)
message = {
'global_merge_vars': [
{'name': 'VERIFICATION_URL', 'content': url},
],
'to': [
{'email': account.email},
],
}
message['from_name'] = message.get('from_name', 'Humanlink')
message['from_email'] = message.get('from_email', 'support#humanlink.co')
try:
md.messages.send_template(
template_name='humanlink-welcome', message=message,
template_content=[], async=True)
except mandrill.Error as e:
logging.exception(e)
raise Exception('Unknown service exception')
The Signup form has an email field, and the data in request.POST should have the email I am sending it with my Client's post method being used in my unit test, so I am really not sure why it still wouldn't have an 'email' attribute.
Form:
class SignUp(forms.Form):
email = forms.EmailField()
password = forms.CharField()
password_conf = forms.CharField()
org_name = forms.CharField()
org_username = forms.CharField()
invite = forms.CharField()
You code suffers from multiple errors. To address your question, in your view method signup you were creating a form, but you shouldn't do form.email or form.password because that's not how django handles form data.
Other related issues, first, you need to call form.is_valid() before you could get any data from form object. Even so, you should use form.cleaned_data['email'] to access the form data.
Secondly. You shouldn't do empty check like that. If you put:
email = forms.EmailField(required=True)
django will automatically verify the emptiness for you already.
Thirdly, raising Exception in views.py method doesn't get your form to return the message to the template you want. If you have custom form validation, you should do it in form class's clean method.
Please check django doc about how to use form properly.

Django template isn't rendering dynamic form errors

I have a Django 1.8 form that contains a paragraph tag that renders either some feedback or a question submitted by a user. It also contains a textarea input 'response_text' and a pair of radio buttons 'close_issue'. This response input can be used to send an optional response to the user. If the user submitted some feedback, the admin should be able to click the 'close issue' radio button and submit the form with no response. However, if the textarea input contains a question, then the form should render an error telling the admin that he/she can't submit the form without typing an answer into the response input. The problem I'm having is that I can't get the form to cause the template to render an error message if the user submitted a question but the admin didn't type in a response. My view, model, form, and template are shown below. forms.py shows all the ways (all commented out) I have tried to make the response input field required if the user submitted a question so that the template will display an error. I also tried overriding the default 'clean' method with one that would raise a ValidationError if the user submitted a question and the response input is blank but that didn't work either. Can anyone tell me what I'm doing wrong?
Thanks.
# view.py
def review_feedback_or_question(request, template, *args, **kwargs):
fqid = kwargs['fqid']## Heading ##
submission = FeedbackQuestion.objects.get(pk=fqid)
if request.method == 'POST':
form = FeedbackQuestionResponseForm(request.POST, submission=submission)
if form.is_valid():
# process the form
return redirect('review-feedback-or-question-queue')
else:
pass
form = FeedbackQuestionResponseForm(submission=submission)
context = {'form': form, 'submission': submission,}
return render(request, template, context)
# models.py
class FeedbackQuestion(models.Model):
SELECT = ''
FEEDBACK = 'feedback'
QUESTION = 'question'
SUBMISSION_TYPE_CHOICES = (
(SELECT , '-- Select --'),
(FEEDBACK, 'Feedback'),
(QUESTION, 'Question'),
)
user = models.ForeignKey(User, related_name="user")
submission_type = models.CharField(max_length=8,
choices=SUBMISSION_TYPE_CHOICES,
default=SELECT)
submission_text = models.TextField()
date_submitted = models.DateTimeField(auto_now_add=True)
response_text = models.TextField()
respondent = models.ForeignKey(User, related_name='respondent')
date_responded = models.DateTimeField(auto_now=True)
issue_closed = models.BooleanField(default=False)
class Meta:
db_table = 'feedback_question'
# forms.py
class FeedbackQuestionResponseForm(forms.Form):
TRUE = 1
FALSE = 0
BLANK = ''
CHOICES = ( (TRUE, 'Yes'), (FALSE, 'No') )
response_text = forms.CharField(
required=False,
label='',
widget=forms.Textarea(attrs={'placeholder': 'Enter response...'}))
close_issue = forms.TypedChoiceField(
choices=CHOICES,
label='Close this issue?',
widget=forms.RadioSelect(renderer=HorizontalRadioRenderer),
coerce=int)
def __init__(self, *args, **kwargs):
if 'submission' in kwargs:
submission = kwargs.pop('submission')
if submission.submission_type == 'question':
# NONE OF THESE WORKED!
#self.fields.get('response_text').required = True
#self.declared_fields['response_text'].required = self.TRUE
#self.declared_fields['response_text'].required = self.TRUE
#self.declared_fields['response_text'].required = True
#self._errors['response_text'] = "You must enter a response"
pass
super(FeedbackQuestionResponseForm, self).__init__(*args, **kwargs)
# template.html
<p>{{ submission.submission_text }}</p>
<form action="" method="post">{% csrf_token %}
{{ form.non_field_errors }}
{% if form.errors %}
{% if form.errors.items|length == 1 %}
Please correct the error below.
{% else %}
Please correct the errors below.
{% endif %}
</p>
{% endif %}
{{ form.response_text.errors }}
{{ form.response_text.label_tag }} {{ form.response_text }}
{{ form.close_issue.errors }}
{{ form.close_issue }} {{ form.close_issue.label_tag }}
<input type="submit" value="Submit" class="" />
</form>
You're not passing submission into the form when you instantiate it on POST, so the required attribute is never being set.
Daniel Roseman was correct in that I need to pass 'submission' into the form when I instantiate the form on POST. But there were still two other problems. First, I need to instantiate the form inside the else block. If this isn't done and the form doesn't validate, then you're passing an unbound form back to the viewer and any errors won't be displayed. Also, it isn't necessary to pass 'submission' to the form when you instantiate it here:
...
else:
form = FeedbackQuestionResponseForm()
context = {...}
...
The next problem was that the order of my statements inside the init method was incorrect. It appears that I needed to execute 'super()' before trying to reference the 'response_text' field. I'll need to locate and study this method in the Django source code to understand exactly why. In any case, this works:
def __init__(self, *args, **kwargs):
if 'submission' in kwargs:
submission = kwargs.pop('submission')
else:
submission = False
super(FeedbackQuestionResponseForm, self).__init__(*args, **kwargs)
if submission:
if submission.submission_type == 'question':
self.fields['response_text'].required = True
else:
self.fields['response_text'].required = False
When the above changes are implemented, the form will make the response_text field required if the user submits a question and an error will be displayed if the admin doesn't enter a response before submitting the form. Many thanks again to Daniel for getting me back on track towards finding a solution.

Form validation using jQuery-Ajax

When it comes to normal POST, GET methods, I usually know my way around.
However, implementing ajax-jQuery into my code to make form validation is proving a huge step for me to learn.
I have a form that has 3 fields:
email, confirm email, and password.
I am using this form to register a new user.
form.py
class UserField(forms.EmailField):
def clean(self, value):
super(UserField, self).clean(value)
try:
User.objects.get(username=value)
raise forms.ValidationError("email already taken.")
except User.DoesNotExist:
return value
class RegistrationForm(forms.Form):
email = UserField(max_length=30, required = True)
conf_email = UserField(label="Confirm Email", max_length=30, required = True)
password = forms.CharField(label="Enter New Password", widget=forms.PasswordInput(), required=True)
def clean(self):
if 'email' in self.cleaned_data and 'conf_email' in self.cleaned_data:
if self.cleaned_data['email'] != self.cleaned_data['conf_email']:
self._errors['email'] = [u'']
self._errors['conf_email'] = [u'Email must match.']
return self.cleaned_data
Html code
<form method="post">
{{ register_form.as_p() }}
<input name = "Register" type="submit" value="Register" />
</form>
I would like that, before I press the submit button, to check if the form is valid and display any relevant error messages, by using ajax-jQuery methods. However, I have no idea how to start / do this.
You might want to look into http://github.com/alex/django-ajax-validation
There is some documentation here and here
You might also look at errors handling with AJAX.
http://garmoncheg.blogspot.com/2013/11/ajax-form-in-django-with-jqueryform.html
It has an accent on how to do it with jQuery form plugin and a dummy views/urls config in order for your task to work. (At least very similar one)