Forms

A Django form is a Python class that defines a set of fields, renders them as HTML inputs, and validates the data a user submits — turning messy, untrusted request data into clean, typed Python values you can safely use.

Learn Forms in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Django course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this lesson you'll define your own Form subclass, wire it into a view using the GET-versus-POST pattern, and add validation that catches bad input before it ever reaches your database.

A Django form is a Python class that subclasses forms.Form . Each field you declare on the class becomes both an HTML input when the form is rendered and a validation rule when the form is processed.

The field type you pick decides how the value is rendered and what counts as valid:

A widget controls the HTML used to render a field. For example, a CharField normally renders a single-line input, but giving it widget=forms.Textarea renders a multi-line box instead.

The same view usually handles both showing an empty form and processing a submitted one. The deciding factor is the HTTP method:

Calling form.is_valid() runs validation and, when it returns True , fills form.cleaned_data — a dictionary of converted, trusted Python values keyed by field name.

The matching template renders the form and the CSRF token:

Notice the template uses {' '} and {'{ }'} . The as_p helper wraps each field in a paragraph; alternatives are as_table and as_ul .

Validation happens in layers. First, each field checks the basics — a required field must have a value, an EmailField must look like an email, an IntegerField must parse as a number. You can add reusable validators to a field, and you can write a clean_<field> method for custom, per-field logic.

A clean_<field> method reads the value from self.cleaned_data , raises forms.ValidationError if something is wrong, and must return the value so it stays in cleaned_data :

Fill in the blanks so the view only reads cleaned_data after the form reports that it is valid.

❌ AttributeError: 'ContactForm' object has no attribute 'cleaned_data'

You read form.cleaned_data before calling form.is_valid() , so the dictionary was never populated.

✅ Fix: only access cleaned_data inside the if form.is_valid(): block.

Your POST template is missing the CSRF token tag.

✅ Fix: add {' '} just inside the <form method="post"> tag.

❌ Submitted form loses its errors and entered values

On an invalid POST you created a fresh empty form instead of re-rendering the bound one.

✅ Fix: render the same bound form object — built from request.POST — so Django shows the errors and the user's input.

Build a tiny form that validates a registration payload: a username of at least 3 characters and an age that is a whole number of 18 or more. Collect every error rather than stopping at the first.

Lesson 10 complete — you can capture and validate user input!

You now know how to define a Form subclass with typed fields and widgets, handle it in a view with the GET-vs-POST pattern, gate on is_valid() , read cleaned_data , and add validators and clean_<field> methods that raise ValidationError .

🚀 Up next: ModelForms — generate a form straight from a model and save records with a single call.

Practice quiz

What is the main advantage of a ModelForm over a plain Form?

  • It is faster to render
  • It generates fields from a model and can .save() to the database
  • It skips validation
  • It requires no template

Answer: It generates fields from a model and can .save() to the database. A ModelForm builds fields from a model and saves a record with one .save() call.

Which method must you call before reading form.cleaned_data?

  • form.clean()
  • form.validate()
  • form.is_valid()
  • form.save()

Answer: form.is_valid(). is_valid() runs validation and populates cleaned_data; reading it earlier raises AttributeError.

What does form.is_valid() populate when it succeeds?

  • form.errors only
  • form.data
  • form.fields
  • form.cleaned_data

Answer: form.cleaned_data. is_valid() fills cleaned_data with the converted Python values.

Where do you declare which model and fields a ModelForm uses?

  • An inner Meta class with model and fields
  • The __init__ method
  • A separate forms.py decorator
  • The model's Meta class

Answer: An inner Meta class with model and fields. A ModelForm uses an inner Meta class specifying model and fields.

How do you add custom validation to a single field?

  • Override save()
  • Define a clean_<fieldname> method
  • Add a validators decorator to the view
  • Override is_valid()

Answer: Define a clean_<fieldname> method. Define clean_<fieldname>, validate, and return the value so it stays in cleaned_data.

What must a clean_<fieldname> method return?

  • True or False
  • The field's value (cleaned or unchanged)
  • An HttpResponse
  • Nothing

Answer: The field's value (cleaned or unchanged). It must return the value so it remains in cleaned_data.

Which method validates across several fields at once?

  • clean_all()
  • validate_together()
  • the form-wide clean() method
  • full_clean_fields()

Answer: the form-wide clean() method. Override the form-wide clean() to validate fields that depend on each other.

What does the csrf_token template tag insert?

  • A submit button
  • A CSS class
  • A visible error list
  • A hidden input with the CSRF token

Answer: A hidden input with the CSRF token. csrf_token adds a hidden input; without it a POST form is rejected with 403.

What is raised to signal a validation failure in a clean method?

  • forms.ValidationError
  • ValueError
  • AssertionError
  • Http404

Answer: forms.ValidationError. Raise forms.ValidationError with a message to flag invalid input.

When should you use a plain Form instead of a ModelForm?

  • When creating or editing a model instance
  • Always
  • For a contact or search form not tied to a table
  • Only for admin pages

Answer: For a contact or search form not tied to a table. A plain Form suits forms that don't map to a database model, like contact or search forms.