ddiipp
ddiipp

Reputation: 205

Custom clean() method throws "NoneType is not iterable" error

As far as I know the clean() method cleans a form according to validation rules defined in forms.py.

For registering users I have created a form like this:

from django import forms
from django.contrib.auth.models import User

class RegistationForm(forms.Form):
    # More fields ...

    username = forms.CharField(
        max_length=30, min_length=3, widget=forms.TextInput(
            attrs={'placeholder': 'Username', 
                   'title': 'You will use this for log in.'}))

    # More fields ...

And for making sure that a new user does not use "@" char in username (and registers only one account with one email) I used this in my RegisterForm's clean method:

def clean(self):
    cleaned_data = super(RegistationForm, self).clean()
    user_email = cleaned_data.get("email")
    user_username = cleaned_data.get("username")
    if "@" in user_username:                              # Line causing error
        msg = u"Usernames may contain alphanumeric, _, +, . and - characters."
        self._errors["username"] = self.error_class([msg]
        del cleaned_data["username"]

    # More validation logic ...
    return cleaned_data

But the problem is when I submit an empty form it gives me an argument of type 'NoneType' is not iterable error in error line shown in clean method.

Shouldn't Django first check if the form is OK and only then check the error line? Or how do I fix it? What's my mistake?

Upvotes: 0

Views: 468

Answers (2)

Daniel Roseman
Daniel Roseman

Reputation: 600059

As itsjeyd says, the error is because username is empty. However, a better solution is to define a clean_username method. This will only be called if the field is not empty, and is the preferred way of validating single fields - clean is best for validating fields that depend on each other. In clean_username you raise forms.ValidationError rather than inserting values on the errors dict.

Upvotes: 3

itsjeyd
itsjeyd

Reputation: 5290

If you leave the username field empty, cleaned_data.get('username') will return None. When checking whether "@" is in user_username, you are telling Python to iterate over the characters in user_username - which is None, so it can't be iterated over.

You could change your check to if user_username and "@" in user_username to guard against the NoneType is not iterable error.

Upvotes: 0

Related Questions