Django form the cleaned_data field is None - django

Django form the cleaned_data field is None.
This field has not passed the validation.
I want to change the value of this field.
Is there another way to get the non-valid fields?
def clean(self):
cleaned_data = super(Form, self).clean()
print(cleaned_data.get('info')) <---- It is None
return cleaned_data

If cleaned_data is None, it should be because your existing form fields have not been validated or there is no data in them.
You can try something like this:
class Form1(forms.Form):
# Your fields here
def clean(self):
if self.is_valid():
return super(forms.Form, self).clean() # Returns cleaned_data
else:
raise ValidationError(...)
EDIT: Taking note of what #Alasdair said - the following approach is better:
You could consider changing the value of 'info' beforehand, i.e. in the view, like so, instead of overriding the form's clean() method:
# In the view
data = request.POST.dict()
data['info'] = # your modifications here
form = Form1(data)
if form.is_valid():
...

Related

django model forms cant change field value in clean()

I have a simple model form, to which I've added a simple checkbox:
class OrderForm(forms.ModelForm):
more_info = models.BooleanField(widget=forms.CheckboxInput())
def clean(self):
if 'more_info' not in self.cleaned_data:
self.instance.details = ""
class Meta:
model = Order
fields = ('details', 'address', ) # more fields
But this does not work and the 'details' fields is still updated by the user value even if the checkbox is not selected (and the if block is executed, debugged). I've also tried changing self.cleaned_data['details'] instead of self.instance.details but it does not work either.
This is not so important, by in the client side I have a simple javascript code which hide/show the details field if the checkbox is selected.
class OrderForm(forms.ModelForm):
more_info = models.BooleanField(required=False)
def clean(self):
cleaned_data = super().clean()
if not cleaned_data['more_info']:
cleaned_data['details'] = ''
return cleaned_data
From Customizing validation:
This method [clean()] can return a completely different dictionary if it wishes, which will be used as the cleaned_data.
Also:
CheckboxInput is default widget for BooleanField.
BooleanField note:
If you want to include a boolean in your form that can be either True or False (e.g. a checked or unchecked checkbox), you must remember to pass in required=False when creating the BooleanField.
Instead of updating cleaned_data, try overriding the save method instead
def save(self, force_insert=False, force_update=False, commit=True, *args, **kwargs):
order = super(OrderForm, self).save(commit=False)
if not self.cleaned_data.get('more_info', False):
order.details = ""
if commit:
order.save()
return order
Additionally, if you want to use the clean method you need to call super's clean first.
def clean(self):
cleaned_data = super(BailiffAddForm, self).clean()
if not cleaned_data.get('more_info', False):
...
return cleaned_data

Override Django ModelForm's Clean_unique method

I am working on a django app where i have a model which have a field with attribute unique=True. I am trying to save data in this model using ModelForm. My model and Model form is like this.
My models.py
class MyModel(models.Model):
field1 = models.CharField(max_length=40, unique=True)
def __unicode__(self):
return self.field1
class DuplicateFields(models.Model):
field1 = models.CharField(max_length=30)
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def clean_field1(self):
value = self.cleaned_data['field1']
if value :
if MyModel.objects.filter(field1=value).count() > 0:
DuplicateFields.objects.create(field1=value)
return Value
raise forms.ValidationError('this field is required')
**I tried below given code also but it also raise Unique field Exception or error **
def clean_unique(form, field, exclude_initial=True,
value = form.cleaned_data.get(field)
if value:
objs = MyModel.objects.filter(field1=value)
if objs.count() > 0:
DuplicateFields.objects.create(field1=value)
return value
def clean_field1(self):
value=clean_unique(self,'field1')
**My Views.py is **
if request.method=='POST':
form = MyModelForm(request.POST)
if form.is_valid():
cleaned_data = form.cleaned_data
field = cleaned_data['field1']
form.save()
return HttpResponse('form has been saved successfully')
else:
print 'form is invalid'
print form._errors
return render_to_response(template_name, {'form':form}, ci)
else:
return render_to_response(template_name, {'form':form}, ci)
What i want to do is while saving the data or calling form.is_valid() method if i found that the data i am trying to store already exists in model then instead of raising a validation error i want to perform some other logic like will store it in some other model.
But in my view when i am calling 'form.is_valid()` it is returning False. Give me some suggestions. Help will be appreciated
To stop giving validate unique modelform exception what you can do is just override the django ModelForm's validate_unique method. like
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def validate_unique(self):
exclude = self._get_validation_exclusions()
try:
self.instance.validate_unique(exclude=exclude)
except forms.ValidationError as e:
try:
del e.error_dict['field1'] #if field1 unique validation occurs it will be omitted and form.is_valid() method pass
except:
pass
self._update_errors(e) #if there are other errors in the form those will be returned to views and is_valid() method will fail.
and in your view check
if form.is_valid():
field1=form.cleaned_data['form1']
try:
MyModel.objects.get(field1=field1)
#write your logic here for duplicate entry
except:
MyModel.objects.create(field1=field1)
return render_to_response('template.html')
else:
return render_to_response('template.html')

Django how to override clean() method in a subclass of custom form?

I created a custom form with custom validation like this:
class MyCustomForm(forms.Form):
# ... form fields here
def clean(self):
cleaned_data = self.cleaned_data
# ... do some cross-fields validation here
return cleaned_data
Now, this form is subclassed with another form which has its own clean method.
What is the correct way to trigger both clean() methods?
At the moment, this is what I do:
class SubClassForm(MyCustomForm):
# ... additional form fields here
def clean(self):
cleaned_data = self.cleaned_data
# ... do some cross-fields validation for the subclass here
# Then call the clean() method of the super class
super(SubClassForm, self).clean()
# Finally, return the cleaned_data
return cleaned_data
It seems to work. However, this makes two clean() methods return cleaned_data which seems to me a bit odd.
Is this the correct way?
You do it well, but you should load cleaned_data from super call like this:
class SubClassForm(MyCustomForm):
# ... additional form fields here
def clean(self):
# Then call the clean() method of the super class
cleaned_data = super(SubClassForm, self).clean()
# ... do some cross-fields validation for the subclass
# Finally, return the cleaned_data
return cleaned_data

Django: why a keyerror instead of a validation error?

why comes a keyerror instead of a validation error when one field is empty? The fields should be required=True by default
class form(forms.ModelForm):
adminAccount = forms.CharField()
adminPassword = forms.CharField(widget=forms.PasswordInput)
def userCheck(self, user, password):
# do something
def clean(self):
self.userCheck(self.cleaned_data['adminAccount'],
self.cleaned_data['adminPassword'])
It is your code that is raising the KeyError here:
self.userCheck(self.cleaned_data['adminAccount'],
self.cleaned_data['adminPassword'])
Because you're trying to access self.cleaned_data[field] when field was not posted.
The documentation provides an example that explains how to validate data that depends on more than one field. According to the examples you should do something like:
cleaned_data = super(form, self).clean()
adminAccount = cleaned_data.get('adminAccount')
adminPassword = cleaned_data.get('adminPassword')
if adminAccount and adminPassword:
# proceed with your validation
return cleaned_data
Also, remember that Form.clean() must return the cleaned_data dict.

django overwrite form clean method

When overwriting a form clean method how do you know if its failed validation on any of the fields? e.g. in the form below if I overwrite the clean method how do I know if the form has failed validation on any of the fields?
class PersonForm(forms.Form):
title = Forms.CharField(max_length=100)
first_name = Forms.CharField(max_length=100)
surname = Forms.CharField(max_length=100)
password = Forms.CharField(max_length=100)
def clean(self, value):
cleaned_data = self.cleaned_data
IF THE FORM HAS FAILED VALIDATION:
self.data['password'] = 'abc'
raise forms.ValidationError("You have failed validation!")
ELSE:
return cleaned_data
Thanks
You can check if any errors have been added to the error dict:
def clean(self, value):
cleaned_data = self.cleaned_data
if self._errors:
self.data['password'] = 'abc'
raise forms.ValidationError("You have failed validation!")
else:
return cleaned_data
BONUS! You can check for errors on specific fields:
def clean(self, value):
cleaned_data = self.cleaned_data
if self._errors and 'title' in self._errors:
raise forms.ValidationError("You call that a title?!")
else:
return cleaned_data
If your data does not validate, your
Form instance will not have a
cleaned_data attribute
Django Doc on Accessing "clean" data
Use self.is_valid().
Although its old post, if you want to apply validations on more than 1 field of same form/modelform use clean(). This method returns cleaned_data dictionary.
To show the errors to users you can use add_error(<fieldname>, "your message") method. This will show the errors along with the field name rather on top of the form. The example is shown below:
add_error() automatically removes the field from cleaned_data dictionary, you dont have to delete it manually. Also you dont have to import anything to use this.
documentation is here
def clean(self):
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
msg = 'passwords do not match'
self.add_error('password2', msg)
return self.cleaned_data
If you just want validation on single field of form/modelform use clean_<fieldname>(). This method will take the values from cleaned_data dictionary and then you can check for logical errors. Always return the value once you are done checking logic.
def clean_password(self):
password = self.cleaned_data['password']
if len(password)<6:
msg = 'password is too short'
self.add_error('password', msg)
return password
Here is a simple example of overriding clean() in django.forms.Form and also using django-braces for AnonymousRequiredMixin to require that only anonymous users visit the Loing Page:
class LoginView(AnonymousRequiredMixin, FormView):
"""
Main Login. And Social Logins
"""
template_name = 'core/login.html'
form_class = LoginForm
success_url = reverse_lazy('blog:index')
def get_success_url(self):
try:
next = self.request.GET['next']
except KeyError:
next = self.success_url
return next
def form_valid(self, form):
cd = form.cleaned_data
user = auth.authenticate(username=cd['login_username'],
password=cd['login_password'])
if user:
auth.login(self.request, user)
messages.info(self.request, 'You are logged in.')
return super(LoginView, self).form_valid(form)