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)
Related
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.
I am struggling a bit with my Django forms. When I call my form site, always validation errors appear (this field is required). I'd prefer to see this message after clicking the submit button, if a field is not filled like a javascript function would do. In addition I'm using regex for validation, which is working fine.
I am working with CVBs. Here is some code:
models.py
class Institute(models.Model):
name = models.CharField(max_length=50)
timestamp = models.DateTimeField(auto_now_add=True)
views.py
class InstituteCreate(CreateView):
model = Institute
form_class = InstituteForm
success_url = reverse_lazy('institute_list')
forms.py
class InstituteForm(forms.ModelForm):
name= forms.CharField(error_messages={'required': 'Own Error Text'}, validators=[RegexValidator(regex='^[a-zA-ZäüößÄÜÖ]*$', message='forbidden string', code='string_invalid')])
class Meta:
model = Institute
fields = ['name']
Hope someone has an idea on how to fix it.
edit1:
my template is quite simple
{% block pagetitle %}Institutes{%endblock %}
{% block content %}
<form class="form-horizontal" name="form_group" method="post">
{% csrf_token %}
<div>
{{ form.as_p }}
</div>
<input class="btn btn-primary" type="submit" value="click me" />
</form>
{% endblock %}
and my url config:
urlpatterns = patterns('',
url(r'^institute_create/$', views.InstituteCreate.as_view(), name='institute_create'),
)
I'm new to Django development so i'll try to explain the problem more detailed:
On my website, when i open the link www.exampleurl.com/institute_create my form is shown. Then i see the field where i have to enter the name for the institute. Above this field the text "this field is required" is displayed. But i don't want to see this, until i try to submit an empty form.
When i enter some text which doesnt match and i press submit button the error text field changes its message to forbidden string as expected.
Unless you're using a POST request to your view, form validation won't be triggered. There's likely an error somewhere else in your code, however, there are couple of things about your code that you'll want to address:
Classes in Python should always begin with an upper-case letter and follow the CapWords convention:
class Institute(models.Model):
name = models.CharField(max_length=50)
# just use the built-in `auto_now_add` argument
timestamp = models.DateTimeField(auto_now_add=True)
class InstituteCreate(CreateView):
model = Institute
form_class = InstituteForm
success_url = reverse_lazy('institute_list')
class InstituteForm(forms.ModelForm):
# All Django model/form fields are required by default, so you
# can drop the `required=True` here
name= forms.CharField(validators=[RegexValidator(regex='^[a-zA-ZäüößÄÜÖ]*$',
message='forbidden string', code='string_invalid')])
class Meta:
model = Institute
fields = ['name']
Otherwise, it's impossible to tell the difference between the class definition and an instance of the class, and you're a lot less likely to run into collisions.
Just out of curiosity, are you seeing in-browser HTML5 validation errors versus errors from Django? If you can add your template code to your question it might help.
I know this is a very old question, but I don't see it answered. I am a beginner in django too and I was following the Django tutorial when I faced the same issue.
I resolved it this way:
if 'voteButton' in request.POST:
context = {
'question': question,
'error_message': "You didn't select a choice"
}
return render(request, 'polls/details.html', context)
elif:
# do something else. Display error message
voteButton is the name of the 'submit' button in your form. Hope this helps! Please do let me know if this approach is wrong.
As Brandon mentioned, your form gets validated on a POST request. So ensure that during the first visit of the page, the Form doesn't get bound to a POST request.
For example, don't do this :
def register(request):
form = RegistrationForm(request.POST)
if request.method == 'POST':
if form.is_valid():
# Do something
return render(request, 'register.html', {'form': form})
You should bind the form to a POST request only if the page is accessed via a POST request. This should help:
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
# DO something
else :
form = RegistrationForm()
return render(request, 'register.html', {'form': form})
I'm trying to create an application where users can send each other messages.
The function I am working on is called read, allows the user to read the message he receives.
The way my model works in the following manner: Every message is related to a thread and this will used to keep track of replied messages related to each other.
My function works by capturing the message id and filtering all the messages related to the message thread. Then I will populate a form with the current message id and allow the user to reply to the form.
When the user submits via POST, I will retrieve the hidden message id and create a new message using the retrieved message id thread.
The issue: I can't figure out how to raise an error for such situation when exceeding the character limit and populating the current message id with the raised error. Can someone kindly help me?
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=30, blank=True)
def __unicode__(self):
return self.user.username
class Thread(models.Model):
subject = models.CharField(max_length=100, blank=True)
user = models.ForeignKey(User)
class Message(models.Model):
user = models.ForeignKey(User, related_name='sender')
recipient = models.ForeignKey(User, related_name='recipient')
created = models.DateTimeField(auto_now_add=True)
body = models.CharField(max_length=1000)
read = models.BooleanField(default=False)
sentmessage = models.BooleanField(default=False)
thread = models.ForeignKey(Thread)
draft = models.BooleanField(default=False)
def __unicode__(self):
return self.body
Views:
#login_required
def read(request,id):
try:
messages = Message.objects.get(pk=id,recipient=request.user)
except Message.DoesNotExist:
return HttpResponseRedirect(reverse('world:Display'))
messages.read = True
messages.save()
if request.method =='POST':
form = ReplyForm(request.POST)
if form.is_valid():
id = request.POST.get('hidden_field', False)
try:
messages = Message.objects.get(pk=id ,recipient=request.user,sentmessage=True,draft=False)
except Message.DoesNotExist or Thread.DOesNotExist:
return HttpResponseRedirect(reverse('world:LoginRequest'))
person = Person.objects.get(user=messages.user)
if person.inbox == "D":
return HttpResponseRedirect(reverse('world:message'))
body = form.cleaned_data['body']
Message.objects.create(user=request.user,recipient=messages.user,body=body,thread=messages.thread,sentmessage=True,read=False)
return HttpResponseRedirect(reverse('world:message'))
message = Message.objects.filter(thread=messages.thread ).filter(created__lte=messages.created)
person = Person.objects.get(user=request.user)
initial = {}
initial.update({'hidden_field': messages.id})
form = ReplyForm(initial=initial)
return render(request,'read.html',{'messages':messages,'form':form,'message':message,'person':person})
forms
class ReplyForm(forms.Form):
body = forms.CharField(widget=forms.Textarea,required=False,max_length=555)
hidden_field = forms.CharField(widget=forms.HiddenInput())
Template:
<div class="box22">
{% for m in message %}
<div class="wrapper">
<div class="user">{{m.user.username}} </div>
<div class="message">{{m.body}}</div>
</div>
{% endfor %}
<form method="POST" >{% csrf_token %}
{{form.body}}{{form.hidden_field}}
<input type = "submit" value= "send" class="sen"/>
</form>
{{form.body.errors}}
First of all, I recommend you use only form.cleaned_data to get submited data.
id = form.cleaned_data['hidden_field']
Also, why you reassign id from request.POST data when you already have id defined in your function args? Maybe it should look like:
msg_response_id = form.cleaned_data['hidden_field']
Then, you always need to check hidden_field value and you can do it with your custom clean method. Add clean_hidden_field method to your form and also you should override init form method and pass id and msg_response_id.
In your views:
form = ReplyForm(initial=initial, id=id, msg_response_id=msg_response_id)
And forms:
class ReplyForm(forms.Form):
def __init__(self, *args, **kwargs):
self.id = kwargs.pop('id', None)
self.msg_response_id = kwargs.pop('msg_response_id', None)
super(ReplyForm, self).__init__(*args, **kwargs)
hidden_field = forms.CharField(widget=forms.HiddenInput())
def clean_hidden_field(self):
if self.id and self.msg_response_id and self.id == self.msg_response_id:
# Raise form error, which will appear in your template.
raise forms.ValidationError(_('You can't reply to your own message.'))
The last paragraph describing what you want is not all too clear, but I believe what you are trying to do, is make an raise an exception when a certain requirement is not met in your form.
If that is the case, then simply catching an ValidationError which is inbuilt into django will do the trick.
So, something like this:
try:
form = ReplyForm(request.POST)
except ValidationError:
# do what you want here
Alternatively,
form = ReplyForm(request.POST)
if form.is_valid():
# do stuff
else:
raise ValidationError
If this does not work for you, then you might try validation the post-data without using django-forms, but usually django takes care of this problem for you, and it will automatically generate the error messages. You can take a deeper look # form validation here.
However if you want even more fine grain control you can make the form yourself, and handle the validation within your views. Otherwise, ValidationError should do the trick and let you redirect the error messages.
Following is the model which I have
class OrgStaff(BaseModel):
user = models.OneToOneField(User)
member_type = models.BooleanField(help_text="1. Read/Write 0. Read Only")
task = models.ForeignKey(ToDos, null=True, blank=True)
org = models.ForeignKey(Org)
# TODO Add possible activities
def __unicode__(self):
return self.user.username
Following is the forms file
class AddStaffForm(ModelForm):
class Meta:
model = OrgStaff
exclude = (
'task',
'org'
)
and this is how I process the view
if request.POST and form.is_valid():
form.save()
ret_url = reverse("some_view", kwargs={
'var':var,})
return redirect(ret_url)
return render(request, "form.html", {"form":form})
This form would render a dropdown, which will show all the users in the database, and a radio box.
But actually, I want to create the form, so that I can add a new user(first name, last name, username, email and password) and then the rest of the fields from the abvoe AddStaffForm.
So question basically boils down to adding fields of userform to the addstaffform.
And then handling them into the views.
Is it doable, or will I have to do it manually?
Can the above model form be extended so that I can first fill in a user detail, and then assign a type to him??
Please let me know, thanks.
Use two separate forms - UserForm, created out of models.User & AddStaffForm but exclude the 'user' field in the AddStaffForm. Use only ONE submit button for both.
So your template will look like:
<form method="post" action="/path/to/wherever">
{{ user_form }}
{{ add_staff_form }}
<button>Submit</button>
</form>
Then, when the user submits the form, process each form independently in the following order:
Process the user form first and save the user instance created by the form to the db. if user_form.is_valid() is True, you can do this by simply doing user = user_form.save()
Next, process the AddStaffForm but pass commit=False (i.e. staff = add_staff_form.save(commit=False) since it does not contain the value for the user field just yet. Provide the user values using staff.user = user and then staff.save()
Provided all other fields in the staff form are provided for (i.e. add_staff_form.is_valid() is otherwise True, this should result in the creation of a new staff instance written to db.
Hope this helps. :)
I am having trouble figuring out how to control field validation for ModelForms.
Here is my Model Form:
class UserForm(ModelForm):
class Meta:
model = User
fields = ('email', 'password')
Here is how I am rendering my form in the template:
<form method="post" action="">
{% csrf_token %}
{{ userform.as_p }}
<input type="submit" value="Submit" />
</form>
Here is my view:
def login_page(request):
if request.method == 'POST':
userform = UserForm(request.POST)
if userform.is_valid():
email = request.POST['email']
password = request.POST['password']
user = authenticate(username=email, password=password)
if user is not None:
login(request, user)
return redirect('/dashboard/')
else:
# How can I give the user feedback about authentication failute here. Right now it just reloads the form without any messages.
return render(request, "login.html", {"userform": userform})
else:
# Because .is_valid() is called, The userform will validate for email addresses and that a password input is present here.
return render(request, "login.html", {"userform": userform})
else:
userform = UserForm()
return render(request, "login.html", {"userform": userform})
From reading the docs, this seems like it should be as simple as passing my form some custom attribute; but since I am working with a ModelForm, I am unsure whether this is achieved in the same way.
Could anyone provide an example or tips on how best to control ModelForm field errors?
Thanks!
Very easy, you have multiple ways to display the error messages:
First one:
1- Override the clean method inside your form/modelform:
def clean(self):
# To keep the main validation and error messages
super(your_form_name, self).clean()
# Now it's time to add your custom validation
if len(self.cleaned_data['password']) < 10:
self._errors['password']='your password\'s length is too short'
# you may also use the below line to custom your error message, but it doesn't work with me for some reason
raise forms.ValidationError('Your password is too short')
Second One
By using django built in validators.
You can use the validators inside the models with the custom error message you want like this:
RE = re.compile('^[0-9]{10}$')
field_name = models.CharField('Name', default='your_name',validators=[RegexValidator(regex=RE, message="Inapproperiate Name!")],)
where validators can utilize multiple built-in validation rules that you can validate against.
please refer to this django documentation
also you can use validators inside your forms definition, but the error message inside validators will not work as it did with models in case of errors, to custom error message use the below third method.
Third Method:
skill = forms.CharField(
label = 'SSkill',
min_length = 2,
max_length = 12,
# message kwarg is only usable in models, yet,
#it doesn't spawn error here.
#validators=[RegexValidator(regex=NME, message="In-approperiate number!")],
required = True,
#Errors dictionary
error_messages={'required': 'Please enter your skill','min_length':'very short entry','invalid':'Improper format'},
#Similar to default you pass in model
initial = 'Extreme Coder'
)
Where, requied, min_length, max_length, along with others, are all fomr kw arguments, where the invalid will only be selected when validators a couple of lines above didn't match the criteria you selected inside validators.
Fourth Method
In this method, you will override your modelform's definition like this:
def __init__(self, *args, **kwargs):
super(Your_Form, self).__init__(*args, **kwargs)
self.fields['password'].error_messages['required'] = 'I require that you fill out this field'
Fifth Method:
I have seen some nice way to custom errors in one of the stackoverflow posts like this:
class Meta:
model = Customer
exclude = ('user',)
fields = ['birthday','name']
field_args = {
"name" : {
"error_messages" : {
"required" : "Please let us know what to call you!"
"max_length" : "Too short!!!"
}
}
}
reference to fifth method is: Brendel's Blog
May be there are other/better ways of doing things, but those are the most common, at least to me :-)
I hope this post helps.
The Django authentication app has a built in AuthenticationForm that you use. If you look at the source code, you can see their approach is to check the username and password inside the clean method. That way, a validation error can be raised if the username and password combination is invalid, and the form will display the error.
You can import the AuthenticationForm and use it in your login view with the following import:
from django.contrib.auth.forms import Authentication
You may also be able to use the built in login view as well. This means you can take advantage of the added functionality, such as displaying a message if the user does not have cookies enabled. It also decreases the chance of you creating a security vulnerability.
If you want to return error or warning messages back to the user (even if there are no errors in the validated form) you can either use the messaging framework, or you can insert custom error messsages into the form.
I think the messaging framework is your best bet - I don't think it's a good idea to inject errors into the form. If someone has entered a wrong username and pword, it's not a validation error, so it shouldn't be treated as such. A validation error should only be thrown if the wrong type of data is entered to a field, not the incorrect value.