I'm trying to clean data in using clean method in forms, but when I did it then I dont see validation errors in my form its only error page from django.
I have edit and create form and I would like to have this clean in one place but not copy to 2 views.
Can you give me some advice? I read docs about clean and valid in forms but I have still problems with that. I give example of it:
Views.py
@user_passes_test(lambda u: u.is_staff, login_url='/account/login/')
def client_create(request):
dict = {}
if request.method == 'POST':
form_user = ClientUserCreateForm(request.POST, prefix="user")
form_client = ClientForm(request.POST, prefix="client")
if form_user.is_valid() and form_client.is_valid():
obj_user = form_user.save(commit=False)
obj_client = form_client.save(commit=False)
obj_user.username = form_client.cleaned_data['vat']
obj_user.set_password(form_client.cleaned_data['vat'])
obj_user.is_active = 1
obj_user.save()
obj_client.id_id = obj_user.id
obj_client.save()
# Redirect to Client profile
return HttpResponseRedirect(reverse('client_profile', args={obj_client.id_id}))
# If forms have error show view again with errors
dict['form_user'] = form_user
dict['form_client'] = form_client
return render(request, 'panel/client/form.html', dict)
else:
dict['form_user'] = ClientUserCreateForm(prefix="user")
dict['form_client'] = ClientForm(prefix="client")
return render(request, 'panel/client/form.html', dict)
Forms.py
class ClientUserCreateForm(forms.ModelForm):
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
email = forms.CharField(required=True)
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
def __init__(self, *args, **kwargs):
super(ClientUserCreateForm, self).__init__(*args, **kwargs)
self.fields['first_name'].widget.attrs.update({
'type': 'text',
'class': 'form-control',
'id': 'input-text',
})
self.fields['last_name'].widget.attrs.update({
'type': 'text',
'class': 'form-control',
'id': 'input-text',
})
self.fields['email'].widget.attrs.update({
'type': 'text',
'class': 'form-control',
'id': 'input-text',
})
def clean(self):
data = self.cleaned_data
first_name = data.get('first_name')
last_name = data.get('last_name')
email = data.get('email')
data['first_name'] = first_name[0].upper() + first_name[1:].lower()
data['last_name'] = last_name[0].upper() + last_name[1:].lower()
data['email'] = email.lower()
return data
class ClientForm(forms.ModelForm):
tags = forms.CharField(widget=forms.Textarea, required=False)
class Meta:
model = Client
fields = ('address', 'zip_code', 'city', 'country', 'forwarding_address',
'forwarding_zip_code', 'forwarding_city', 'forwarding_country',)
def __init__(self, *args, **kwargs):
super(ClientForm, self).__init__(*args, **kwargs)
self.fields['country'].queryset = CountriesChoices.objects.all()
self.fields['forwarding_country'].queryset = CountriesChoices.objects.all()
self.fields['country'].initial = 1
self.fields['address'].widget.attrs.update({
'type': 'text',
'class': 'form-control',
'id': 'input-text',
})
self.fields['zip_code'].widget.attrs.update({
'type': 'text',
'class': 'form-control',
'id': 'input-text',
})
self.fields['city'].widget.attrs.update({
'type': 'text',
'class': 'form-control',
'id': 'input-text',
})
self.fields['country'].widget.attrs.update({
'class': 'form-control',
})
def clean(self):
data = self.cleaned_data
address = data.get('address')
zip_code = data.get('zip_code')
city = data.get('city')
forwarding_address = data.get('forwarding_address')
forwarding_zip_code = data.get('forwarding_zip_code')
forwarding_city = data.get('forwarding_city')
data['address'] = address[0].upper() + address[1:].lower()
data['zip_code'] = zip_code
data['city'] = city[0].upper() + city[1:].lower()
if len(forwarding_address) > 0:
data['forwarding_address'] = forwarding_address[0].upper() + forwarding_address[1:].lower()
else:
data['forwarding_address'] = address[0].upper() + address[1:].lower()
if len(forwarding_zip_code) > 0:
data['forwarding_zip_code'] = forwarding_zip_code
else:
data['forwarding_zip_code'] = zip_code
if len(forwarding_city) > 0:
data['forwarding_city'] = forwarding_city[0].upper() + forwarding_city[1:].lower()
else:
data['forwarding_city'] = city[0].upper() + city[1:].lower()
return data
For example i leave field "first_name" empty and then i got error django page with: 'NoneType' object is not subscriptable(traceback below) except form page with error "This field is required"(when i comment clean method).
Traceback
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8000/panel/client/edit/6/
Django Version: 1.8.8
Python Version: 3.5.1
Installed Applications:
('django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core',
'api',
'client',
'registration',
'avatar',
'filer',
'mptt',
'easy_thumbnails',
'reversion')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware')
Traceback:
File "C:\Users\loc\dJangoEnvironment\lib\site-packages\django\core\handlers\base.py" in get_response
132. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\loc\dJangoEnvironment\lib\site-packages\django\contrib\auth\decorators.py" in _wrapped_view
22. return view_func(request, *args, **kwargs)
File "C:\Users\loc\PycharmProjects\pro\core\views.py" in client_edit
192. if form_user.is_valid() and form_client.is_valid():
File "C:\Users\loc\dJangoEnvironment\lib\site-packages\django\forms\forms.py" in is_valid
184. return self.is_bound and not self.errors
File "C:\Users\loc\dJangoEnvironment\lib\site-packages\django\forms\forms.py" in errors
176. self.full_clean()
File "C:\Users\loc\dJangoEnvironment\lib\site-packages\django\forms\forms.py" in full_clean
393. self._clean_form()
File "C:\Users\loc\dJangoEnvironment\lib\site-packages\django\forms\forms.py" in _clean_form
417. cleaned_data = self.clean()
File "C:\Users\loc\PycharmProjects\pro\core\forms.py" in clean
421. data['first_name'] = first_name[0].upper() + first_name[1:].lower()
Exception Type: TypeError at /panel/client/edit/6/
Exception Value: 'NoneType' object is not subscriptable
form. cleaned_data returns a dictionary of validated form input fields and their values, where string primary keys are returned as objects. form. data returns a dictionary of un-validated form input fields and their values in string format (i.e. not objects).
The clean() method on a Field subclass is responsible for running to_python() , validate() , and run_validators() in the correct order and propagating their errors. If, at any time, any of the methods raise ValidationError , the validation stops and that error is raised.
The is_valid() method is used to perform validation for each field of the form, it is defined in Django Form class. It returns True if data is valid and place all data into a cleaned_data attribute.
The field argument is the name of the field to which the errors should be added. If its value is None the error will be treated as a non-field error as returned by Form. non_field_errors() . The error argument can be a string, or preferably an instance of ValidationError .
You should do validation like that in the individual clean_<fieldname>
methods. Those will only be called if the content is already valid and populated. So:
def clean_firstname(self):
first_name = self.cleaned_data['first_name']
return first_name[0].upper() + first_name[1:].lower()
def clean_last_name(self):
last_name = self.cleaned_data['last_name']
return last_name[0].upper() + last_name[1:].lower()
def clean_email(self):
email = self.cleaned_data['email']
return email.lower()
Note also your first_name and last_name validation could be simplified by using last_name.capitalize()
, which converts to exactly the format you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With