Django
Django Forms
Web Development
Python
Backend Development

Django Application, Django forms

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Django forms sit at the boundary between the browser and your application logic. They solve three common problems at once: rendering HTML inputs, validating submitted data, and converting raw strings into Python values your code can trust.

Defining a Form Class

The simplest form inherits from forms.Form. You declare fields as class attributes, and Django builds validation rules from those definitions. This keeps request parsing out of the view and gives you a single place to describe acceptable input.

python
1from django import forms
2
3
4class ContactForm(forms.Form):
5    name = forms.CharField(max_length=100)
6    email = forms.EmailField()
7    message = forms.CharField(widget=forms.Textarea, min_length=10)
8    subscribe = forms.BooleanField(required=False)

When Django binds submitted data to this form, each field validates its own type and constraints. EmailField checks email syntax, CharField enforces length, and optional fields can be left blank when required=False.

This is better than reading values directly from request.POST, because the form becomes an explicit contract. If the request changes later, the validation rules stay close to the data definition.

Processing Submitted Data in a View

A typical view creates an unbound form for GET requests and a bound form for POST requests. Calling is_valid() runs field validation and any custom cleaning methods.

python
1from django.shortcuts import render
2from .forms import ContactForm
3
4
5def contact_view(request):
6    if request.method == "POST":
7        form = ContactForm(request.POST)
8        if form.is_valid():
9            cleaned = form.cleaned_data
10            print("Name:", cleaned["name"])
11            print("Email:", cleaned["email"])
12            print("Subscribed:", cleaned["subscribe"])
13            return render(request, "contact_success.html", {"email": cleaned["email"]})
14    else:
15        form = ContactForm()
16
17    return render(request, "contact.html", {"form": form})

The important detail is cleaned_data. That dictionary exists only after successful validation and contains converted values, not raw strings. For example, a checkbox becomes a Python boolean instead of an unchecked or checked browser payload.

Adding Custom Validation

Built-in field validation handles many cases, but most applications need business rules too. Django lets you validate one field with a clean_fieldname method or validate combinations of fields with clean().

python
1from django import forms
2
3
4class SignupForm(forms.Form):
5    username = forms.CharField(max_length=30)
6    password = forms.CharField(widget=forms.PasswordInput)
7    confirm_password = forms.CharField(widget=forms.PasswordInput)
8
9    def clean_username(self):
10        username = self.cleaned_data["username"]
11        if "admin" in username.lower():
12            raise forms.ValidationError("Choose a less confusing username.")
13        return username
14
15    def clean(self):
16        cleaned = super().clean()
17        password = cleaned.get("password")
18        confirm = cleaned.get("confirm_password")
19
20        if password and confirm and password != confirm:
21            raise forms.ValidationError("Passwords must match.")
22
23        return cleaned

This approach keeps validation messages close to the form instead of scattering checks across controllers, templates, and model code.

Using ModelForm for Database Records

If a form maps directly to a model, forms.ModelForm reduces boilerplate. Django can derive fields from the model and save the instance when validation passes.

python
1from django import forms
2from .models import Article
3
4
5class ArticleForm(forms.ModelForm):
6    class Meta:
7        model = Article
8        fields = ["title", "body", "published"]
python
1from django.shortcuts import redirect, render
2from .forms import ArticleForm
3
4
5def create_article(request):
6    form = ArticleForm(request.POST or None)
7    if request.method == "POST" and form.is_valid():
8        form.save()
9        return redirect("article-list")
10    return render(request, "article_form.html", {"form": form})

Use ModelForm when the form mostly reflects model structure. Use plain Form when the input is not a direct database record, such as a search form, contact form, or multi-step workflow.

Rendering Forms in Templates

Django can render the whole form quickly, but explicit field rendering gives you better control over layout and error placement.

html
1<form method="post">
2  {% csrf_token %}
3  <div>
4    {{ form.name.label_tag }}
5    {{ form.name }}
6    {{ form.name.errors }}
7  </div>
8  <div>
9    {{ form.email.label_tag }}
10    {{ form.email }}
11    {{ form.email.errors }}
12  </div>
13  <button type="submit">Send</button>
14</form>

This makes it easier to style individual inputs, place help text near the right field, and show errors where users expect them.

Common Pitfalls

  • Reading directly from request.POST after calling is_valid(). Use form.cleaned_data so you get validated, converted values.
  • Putting database writes before validation. Save or update records only after form.is_valid() returns True.
  • Using ModelForm for every situation. Plain forms are often clearer for workflows that do not match a single model.
  • Forgetting csrf_token in the template. A valid form class does not bypass Django's CSRF protection.
  • Hiding validation rules in the view instead of the form. That makes behavior harder to test and easier to duplicate incorrectly.

Summary

  • Django forms centralize input rendering, validation, and cleaning.
  • 'forms.Form is best for custom workflows and non-model input.'
  • 'ModelForm is useful when form fields map closely to a database model.'
  • 'cleaned_data should be the main source of trusted input after validation.'
  • Explicit template rendering gives better control over layout and error handling.

Course illustration
Course illustration

All Rights Reserved.