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.