Forms

request.POST binding to wrong parameter in forms

This is a common idiom in a view.:

def view_func(request):
    form = FormClass()
    if request.method == 'POST':
        form=FormClass(request.POST)#Gotcha
        ....
    payload = {'form':form}
    return render_to_response(...)

Now suppose we edited our form class to:

class FormClass(forms.Form):
    def __init__(self, user = None, *args, **kwargs):
        ...

request.POST will bind to user, when we meant to be the POST data.

Solution:

Rewrite the gotcha line as

form=FormClass(data=request.POST)

Using form.cleaned_data before calling form.is_valid

Even if you are sure your form passes validation, you still need to call is_valid. form.cleaned_data is calculated after form.is_valid is called, which you probably are using in your form.save().

Overriding form.save in ModelForms:

Similar to models.save, forms.save are often (wrongly) overriden as forms.save:

def forms.save(self):
    ...
    super(FormCLass, self).save()

This won’t work in many cases, for example form.save(commit=False)

Solution:

Always save as:

def forms.save(self, *args, **kwargs):
    ...
    super(FormClass, self).save(*args, **kwargs)

Not calling superclass __init__

You might want to change the widget of a particular form field and this can be done by overriding Form’s __init__.:

from django.contrib.admin.widgets import AdminFileWidget

class FormClass(forms.ModelForm):

    class Meta:
        model = Profile

    def __init__(self, *args, **kwargs):
        self.fields['picture'].widget = AdminFilewidget() #Gotcha

self.fields is populated after __init__ of ModelForm has executed. So, make sure to call superclass __init__ before accessing self.fields.:

def __init__(self, *args, **kwargs):
    super(FormClass, self).__init__(*args, **kwargs)
    self.fields['picture'].widget = AdminFilewidget()