django/django
Forms
django/forms/ is the form library: validation, HTML rendering, and a model-bound dialect (ModelForm) that hooks the ORM in so model definitions become create/update forms with one line of glue.
Purpose
Take an HTTP request body, validate it against a declarative schema, and either return a Python data structure or render the schema with errors back to the user as HTML. The framework supports plain forms, model-bound forms, formsets (collections of forms), and inline formsets (parent + child relationship).
Directory layout
django/forms/
├── __init__.py
├── boundfield.py # BoundField: a (form, field, name) triple used at render time
├── fields.py # Field classes: CharField, IntegerField, DateField, EmailField, … (~49 KB)
├── forms.py # Form, BaseForm; the declarative form class
├── formsets.py # BaseFormSet, ManagementForm, formset_factory
├── models.py # ModelForm, BaseModelFormSet, inlineformset_factory (~62 KB)
├── renderers.py # form template renderers (DjangoTemplates / Jinja2 / DjangoDivFormRenderer)
├── widgets.py # Widget classes: TextInput, CheckboxInput, Select, … (~41 KB)
├── utils.py # ErrorDict, ErrorList, pretty_name
├── jinja2/ # Jinja2 templates for form rendering
└── templates/ # Django templates for form renderingKey abstractions
| Type | File | Role |
|---|---|---|
Form / BaseForm |
forms.py |
Declarative form class users subclass |
Field |
fields.py |
A single form field; validates and coerces |
Widget |
widgets.py |
The HTML rendering of a field |
BoundField |
boundfield.py |
A field bound to a form instance for rendering |
ErrorList, ErrorDict |
utils.py |
Per-field and per-form error containers |
BaseFormSet |
formsets.py |
A collection of forms |
ModelForm |
models.py |
A form derived from a model's fields |
BaseModelFormSet |
models.py |
A formset of model-bound forms |
BaseInlineFormSet |
models.py |
A formset for child rows of a parent model |
Renderer |
renderers.py |
Resolves form templates |
How it works
graph TD
Request["request.POST"]
Form["MyForm(data=request.POST)"]
Bound["form.is_bound = True"]
Validate["form.is_valid()<br/>→ form.full_clean()"]
PerField["field.clean(value):<br/>to_python → validate → run_validators"]
Form_clean["form.clean()<br/>(cross-field validation)"]
Cleaned["form.cleaned_data"]
Errors["form.errors"]
Request --> Form
Form --> Bound
Bound --> Validate
Validate --> PerField
PerField --> Form_clean
Form_clean --> Cleaned
PerField -->|on error| Errors
Form_clean -->|on error| ErrorsDeclarative metaclass
Form is constructed by DeclarativeFieldsMetaclass. The metaclass scans the class body for Field instances and stores them in base_fields. At instance time, each Field becomes a BoundField for rendering.
Field declaration order is preserved (Python 3.7+ dicts are ordered) so rendering matches the source.
Validation pipeline
form.is_valid() calls form.full_clean(), which:
_clean_fields()— for each field, get the raw value fromdata, callfield.clean(value).clean()is a three-step pipeline:to_python(value)— type coercion.validate(value)— basic validity (required, allowed choices).run_validators(value)— additionalvalidators=[]from the field declaration.
_clean_form()— callform.clean()for cross-field rules. Override on subclasses._post_clean()—ModelFormuses this to run model-level validators (Model.full_clean()).
After full_clean(), form.cleaned_data and form.errors are populated.
Rendering
Calling str(form) (or form.as_p(), form.as_div(), etc.) renders the form via the configured renderer. The renderer resolves a template (django/forms/templates/django/forms/p.html, div.html, etc.) and feeds it the bound form. Each field gets a BoundField that knows how to render its widget, label, and errors.
The default in 5.x+ is as_div, which uses <div> blocks instead of the older <p> or <table> rendering.
Widgets
A Widget is a Python class that knows how to render a field as HTML and how to extract the field's value from request data. Built-in widgets cover the common HTML inputs (TextInput, Textarea, Select, SelectMultiple, CheckboxInput, RadioSelect, FileInput, DateInput, etc.) and a few composites (SplitDateTimeWidget, MultiWidget).
Widgets have their own template files under templates/django/forms/widgets/.
ModelForm
ModelForm (forms/models.py) is the bridge to the ORM. The metaclass walks Meta.model._meta.fields and creates a Field for each one via formfield_callback. The default mapping lives on each model field: CharField.formfield() returns a forms.CharField, etc.
ModelForm.save():
- Calls
Model.full_clean()(via_post_clean). - Sets the cleaned values on the model instance.
- If
commit=True, callsModel.save(). - Returns the model instance.
For ManyToManyFields, the form has to hold the values until after save(commit=True) because M2M relations require the parent to have a primary key.
Formsets
formset_factory(MyForm, extra=2) creates a BaseFormSet subclass. The formset:
- Manages a list of bound forms.
- Renders a hidden
ManagementFormwithtotal_form_count,initial_form_count,max_num_form_count, and a hiddenprefix. - Validates each form individually plus a formset-level
clean().
modelformset_factory and inlineformset_factory return formsets that work with ModelForms, including the parent-child relationship for inline formsets.
Integration points
- ORM (orm) — model fields define
formfield()to produce form fields;ModelFormconsumes that. - Views (views) —
FormView,CreateView,UpdateView,DeleteViewintegrate the validation/render cycle. - Templates (templates) — form rendering is template-driven; both DTL and Jinja2 templates live under
forms/templates/andforms/jinja2/. - Admin (
contrib/admin/) — the admin's change/add forms are heavily customisedModelForms. - Validators (
django/core/validators.py) — most form fields delegate to validators. - i18n — error messages use
gettext_lazy.
Entry points for modification
- Custom field: subclass
Fieldinforms/fields.py. Overrideto_python,validate,run_validators. Pair with aWidgetif needed. - Custom widget: subclass
Widgetinforms/widgets.py. Overrideformat_value,get_context,value_from_datadict. Add a template file for rendering. - Custom renderer: subclass
BaseRendererinforms/renderers.py. SetFORM_RENDERERin settings. ModelFormfield defaults: changeformfield_callbackin yourModelForm.Meta, or addformfield()to a custom model field.
Key source files
| File | Purpose |
|---|---|
django/forms/forms.py |
Form, BaseForm, DeclarativeFieldsMetaclass |
django/forms/fields.py |
Field classes (~49 KB) |
django/forms/widgets.py |
Widget classes (~41 KB) |
django/forms/models.py |
ModelForm, formset factories, BaseInlineFormSet (~62 KB) |
django/forms/formsets.py |
BaseFormSet, ManagementForm, formset_factory |
django/forms/boundfield.py |
BoundField |
django/forms/renderers.py |
Form template renderers |
django/forms/utils.py |
ErrorList, ErrorDict, pretty_name |
Where to read tests
tests/forms_tests/— exhaustive form, field, widget coverage.tests/model_forms/—ModelFormintegration with the ORM.tests/forms_tests/tests/test_formsets.py,test_inlineformsets.py— formset behaviour.tests/admin_views/— the admin exercises forms end-to-end.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.