Django antipatterns 〉antipattern 〉Constructing a new form when validation fails Fork me on GitHub

Often in a view a new form is constructed when validating a bounded form fails, for example:

from django.shortcuts import redirect, render

def my_view(request):
    if request.method == 'POST':
        form = MyForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('name-of-some-view')
        else:
            form = MyForm()
    else:
        form = MyForm()
    return render(request, 'name-of-some-template.html', {'form': form})

Why is it a problem?

A Form (and ModelForm) is not only useful to render HTML forms, validate input and save data to the database. It also generates error messages. If you render an invalid form correctly, then it will show the error messages near the fields, and the non-field specific error messages at the top of the form (or at another place if you manually render this).

What can be done to resolve the problem?

Omit constructing a new form. In case form.is_valid() returns False, just render that form, and not a new one, so the view can be modified to:

from django.shortcuts import redirect, render

def my_view(request):
    if request.method == 'POST':
        form = MyForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('name-of-some-view')
        # no new form
    else:
        form = MyForm()
    return render(request, 'name-of-some-template.html', {'form': form})

Extra tips

The Django documentation has a section named rendering fields manually that explains how to render a form that includes rendering error messages.