Action Dispatch¶
This page covers the form dispatch pipeline.
It traces a submission from the template {% form %} tag through the validation chain to the handler and the re-render path.
Overview¶
The dispatcher runs at /_next/form/<uid>/ where the UID is the first 16 hex characters of the SHA-256 digest of the action name.
The dispatcher loads the action handler, builds the form, runs the validation chain, and either calls the handler or re-renders the origin page.
Any non-POST method short-circuits before that work and returns HTTP 405.
Pipeline¶
flowchart TB
Template["form tag in template"] --> Endpoint["form dispatch endpoint"]
Endpoint -- "non-POST" --> NotAllowed["HTTP 405"]
Endpoint -- POST --> Lookup["Resolve action by UID"]
Lookup -- unknown UID --> NotFound["HTTP 404"]
Lookup -- "found, no form_class" --> HandlerOnly["Run handler only"]
Lookup -- "found, form_class" --> Build["Build form"]
HandlerOnly --> HandlerOnlyResponse["Handler response or HTTP 204"]
HandlerOnly --> ActionDispatched["action_dispatched signal"]
Build --> Validate{"Form valid"}
Validate -- yes --> Handler["Run handler"]
Handler --> Response["Handler response"]
Handler --> ActionDispatched
Validate -- no --> Origin{"Origin page valid"}
Origin -- no --> BadRequest["HTTP 400"]
Origin -- yes --> ShareCache["Reuse dep cache on request"]
ShareCache --> RenderOrigin["Render origin page"]
RenderOrigin --> RerenderHTML["HTTP 200 with bound form"]
Validate -- no --> FormFailed["form_validation_failed signal"]
Modules¶
next.forms.decorators.@actiondecorator implementation. An@actionmay also live in acomponent.py, which the components backend imports during component discovery, so the action registry is populated before the first request regardless of where the decorator runs. See Component Pipeline for the discovery walk.next.forms.manager.FormActionManageraggregates the configured backends and yields their URL patterns. The per-action registry lives on eachRegistryFormActionBackend, not on the manager.next.forms.dispatch.FormActionDispatchruns the pipeline per request. Manages the bound form, the dependency cache reuse, and the response selection.next.forms.backends.FormActionBackendabstract contract,RegistryFormActionBackenddefault implementation, andFormActionFactory.next.forms.uid.redirect_to_originandvalidated_next_form_page_pathhelpers for the origin page round trip.next.forms.markers.DFormannotation andFormProviderclass.next.forms.serializers.FormSpec,FormsetSpec,FormsetRowSpec,FormSectionSpec,FieldSpecplus the buildersform_spec,formset_spec,field_spec.next.forms.formsets.cleanup_extra_initialhelper for blank extra rows.
Origin Page Validation¶
The hidden _next_form_page field on every rendered form carries the absolute path to the origin page.py.
The dispatcher resolves the path and accepts it only when the basename is page.py, the resolved path lives under BASE_DIR, and either the file exists or a sibling template.djx does.
The sibling template.djx clause is the virtual-route exception: a directory routed by its template alone has no page.py on disk yet still resolves a valid origin.
A blank field, an OSError while resolving, an unset BASE_DIR, or a path outside BASE_DIR all return HTTP 400.
Backends¶
The DEFAULT_FORM_ACTION_BACKENDS setting lists the active backends.
Each backend is a full implementation of the FormActionBackend contract, not a step in a middleware chain.
A backend owns the registry, the URL generation, and the dispatch for every action it registers.
The default value registers RegistryFormActionBackend.
Its dispatch method resolves the UID to an action and forwards the request to FormActionDispatch, which builds the form, runs the validation chain, and validates the origin page when re-rendering.
A project customises dispatch by subclassing RegistryFormActionBackend and overriding dispatch.
The override calls super().dispatch to keep the standard pipeline.
Signals¶
One signal fires at import time, the other two fire per request.
action_registeredfires at import time, once per@actionwhen the registry receives it.form_validation_failedfires at request time, once per failing submission.action_dispatchedfires at request time, once per successful handler invocation, with the action name, the bound form (Nonefor form-less actions), the URL kwargs, the handler duration, the response status, and the dispatch dependency cache in the payload.
Extension Points¶
Subclass
RegistryFormActionBackendand overridedispatchto wrap the standard pipeline.Register the custom backend through
DEFAULT_FORM_ACTION_BACKENDS.Subscribe to
action_dispatchedfor audit and cache invalidation.Subscribe to
form_validation_failedfor alerting on failure rates.
See Also¶
See also
Forms for the topic subtree. Validation and Re-render for the failure flow.