Skip to main content

Django Form Validation State Machine

The Django Form validation process is a state machine that transitions a form from an initial instantiation to a validated state.

A form starts as either Forms and Validation (no data provided) or django.forms.boundfield (data/files provided). The validation process is lazily triggered by accessing the errors property or calling is_valid().

The core of the state machine is the full_clean() method, which orchestrates three main phases:

  1. Field Cleaning: Each field's clean() method is called (performing to_python, validate, and run_validators), followed by any custom clean_<fieldname>() methods on the form.
  2. Form Cleaning: The form's clean() method is called for cross-field validation.
  3. Post Cleaning: An internal hook (_post_clean()) used primarily by ModelForm to perform model-level validation and unique checks.

During these phases, any ValidationError encountered is captured via add_error(), which populates the _errors dictionary and removes the corresponding field from cleaned_data. A form is considered Overview of the Validation API only if it is bound and the _errors collection is empty after cleaning.

Key Architectural Findings:

  • Forms are either Unbound (is_bound=False) or Bound (is_bound=True) upon instantiation.
  • Validation is lazy: full_clean() is only called when errors or is_valid() are accessed.
  • The full_clean() method resets the _errors dictionary and populates cleaned_data.
  • Field-level validation involves a sequence: to_python -> validate -> run_validators -> clean_<field>().
  • ModelForm extends the state machine via _post_clean() to include model instance validation and unique constraints.
  • add_error() is the primary mechanism for state transition to 'Invalid', ensuring cleaned_data is kept in sync by removing failing fields.
Loading diagram...