Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django forms clean data

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
like image 957
Thaian Avatar asked Apr 19 '16 07:04

Thaian


People also ask

What is form cleaned data in Django?

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).

What is clean method in Django?

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.

What is form Is_valid () in Django?

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.

What is form Non_field_errors?

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 .


1 Answers

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.

like image 180
Daniel Roseman Avatar answered Sep 19 '22 10:09

Daniel Roseman