Forms Reference¶
Module Summary¶
next.forms exposes form action registration, dispatch, formset helpers, frozen field and form specs, and a curated set of commonly used Django form fields and widgets.
It also re-exports page from next.pages so that a single from next.forms import action, page covers the two most common decorators in a page.py.
API Tiers¶
next.forms groups its symbols into three tiers that describe the intended audience for each name.
The lists below are representative.
The autodoc blocks under Public API are the exhaustive surface.
- Stable.
@action,page,Form,ModelForm,BaseForm,BaseModelForm,DForm,FormActionManager,form_action_manager, and the UID helpers (FORM_ACTION_REVERSE_NAME,URL_NAME_FORM_ACTION,redirect_to_origin). Use these in application code.- Advanced.
FormProvider,FormActionBackend,FormActionFactory,RegistryFormActionBackend,FormActionDispatch,FormActionOptions,ActionMeta,build_form_namespace_for_action,validated_next_form_page_path, the frozen specs (FieldSpec,FormsetSpec,FormSpec,FormSectionSpec,FormsetRowSpec,FieldKind), the spec helpers (field_spec,form_spec,formset_spec), the formset helpercleanup_extra_initial, and thesignalsandcheckssubmodules. Use these when writing a custom backend or a form renderer.FormProviderauto-registers through the__init_subclass__hook onRegisteredParameterProviderand resolves the boundformparameter, so application code never instantiates it.- Internal hooks.
Symbols with a leading underscore are implementation details re-exported for testing and advanced backend authoring. The full set lives in
next.forms.__all__, which is the source of truth for the internal hook surface. Do not import these names in application code.
Public API¶
Decorator¶
- next.forms.action(name: str, *, form_class: type[django_forms.Form] | Callable[..., type[django_forms.Form]] | None = None, namespace: str | None = None) Callable[[Callable[..., Any]], Callable[..., Any]][source]¶
Register a named form action. Names must be unique across the project.
Pass namespace=”app_label” to prefix the stored key with “app_label:”, which lets two apps use the same short name without colliding. Reverse is by the namespaced name.
form_class may be a Form subclass or a callable that returns one when called. Factory callables are dependency-resolved at dispatch time with the request and URL kwargs, which lets admin-style handlers shape the form per request (for example via ModelAdmin.get_form()).
Form Base Classes¶
- class next.forms.Form(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, field_order=None, use_required_attribute=None, renderer=None, bound_field_class=None)[source]¶
A collection of fields with their associated data.
This extends Django’s Form with get_initial support.
- base_fields = {}¶
- declared_fields = {}¶
- property media¶
Return all media required to render the widgets on this form.
- class next.forms.ModelForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]¶
Form for editing a model instance.
This extends Django’s ModelForm with get_initial support.
- base_fields = {}¶
- declared_fields = {}¶
- property media¶
Return all media required to render the widgets on this form.
- class next.forms.BaseForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, field_order=None, use_required_attribute=None, renderer=None, bound_field_class=None)[source]¶
Custom BaseForm that extends Django’s BaseForm with get_initial.
- classmethod get_initial() dict[str, Any][source]¶
Return initial data for this form.
Override this method to provide initial data. Subclasses can declare whichever DI parameters they need (request: HttpRequest, URL kwargs, or named dependencies). The dispatcher resolves them via the standard DI pipeline before invoking the override. The returned dictionary becomes the initial parameter passed to the form constructor.
- class next.forms.BaseModelForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]¶
Custom BaseModelForm with get_initial support.
- classmethod get_initial() dict[str, Any] | object[source]¶
Return initial data or a model instance for this form.
For ModelForm subclasses this may return either a dictionary, which becomes the initial parameter and results in a new instance on save, or a model instance, which becomes the instance parameter and updates the existing record. Subclasses may declare DI parameters in the override. The dispatcher resolves them automatically.
Fields and Widgets¶
The framework re-exports a curated set of commonly used Django form fields and widgets through next.forms so a single import covers most form definitions.
Import any other Django field or widget directly from django.forms.
Custom BaseForm and BaseModelForm plus Django form-class re-exports.
BaseForm and BaseModelForm extend Django with get_initial, which lets @action resolve initial data from the request and URL kwargs before binding the form. Form and ModelForm apply the right metaclass so declarative field syntax continues to work. The Django form classes re-exported below are a convenience so user code can do from next.forms import CharField, EmailField without reaching into Django directly.
- class next.forms.base.BooleanField(*, required=True, widget=None, label=None, initial=None, help_text='', error_messages=None, show_hidden_initial=False, validators=(), localize=False, disabled=False, label_suffix=None, template_name=None, bound_field_class=None)[source]¶
- widget¶
alias of
CheckboxInput
- class next.forms.base.CharField(*, max_length=None, min_length=None, strip=True, empty_value='', **kwargs)[source]¶
- class next.forms.base.CheckboxInput(attrs=None, check_test=None)[source]¶
- input_type = 'checkbox'¶
- template_name = 'django/forms/widgets/checkbox.html'¶
- value_from_datadict(data, files, name)[source]¶
Given a dictionary of data and this widget’s name, return the value of this widget or None if it’s not provided.
- property media¶
- class next.forms.base.ChoiceField(*, choices=(), **kwargs)[source]¶
-
- default_error_messages = {'invalid_choice': 'Select a valid choice. %(value)s is not one of the available choices.'}¶
- property choices¶
- class next.forms.base.DateField(*, input_formats=None, **kwargs)[source]¶
-
- input_formats = ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%b %d %Y', '%b %d, %Y', '%d %b %Y', '%d %b, %Y', '%B %d %Y', '%B %d, %Y', '%d %B %Y', '%d %B, %Y']¶
- default_error_messages = {'invalid': 'Enter a valid date.'}¶
- class next.forms.base.DateInput(attrs=None, format=None)[source]¶
- format_key = 'DATE_INPUT_FORMATS'¶
- template_name = 'django/forms/widgets/date.html'¶
- property media¶
- class next.forms.base.DateTimeField(*, input_formats=None, **kwargs)[source]¶
- widget¶
alias of
DateTimeInput
- input_formats = <django.forms.fields.DateTimeFormatsIterator object>¶
- default_error_messages = {'invalid': 'Enter a valid date/time.'}¶
- class next.forms.base.DateTimeInput(attrs=None, format=None)[source]¶
- format_key = 'DATETIME_INPUT_FORMATS'¶
- template_name = 'django/forms/widgets/datetime.html'¶
- property media¶
- class next.forms.base.DecimalField(*, max_value=None, min_value=None, max_digits=None, decimal_places=None, **kwargs)[source]¶
- default_error_messages = {'invalid': 'Enter a number.'}¶
- __init__(*, max_value=None, min_value=None, max_digits=None, decimal_places=None, **kwargs)[source]¶
- class next.forms.base.EmailField(**kwargs)[source]¶
- widget¶
alias of
EmailInput
- default_validators = [<django.core.validators.EmailValidator object>]¶
- class next.forms.base.EmailInput(attrs=None)[source]¶
- input_type = 'email'¶
- template_name = 'django/forms/widgets/email.html'¶
- property media¶
- class next.forms.base.FileField(*, max_length=None, allow_empty_file=False, **kwargs)[source]¶
- widget¶
alias of
ClearableFileInput
- default_error_messages = {'contradiction': 'Please either submit a file or check the clear checkbox, not both.', 'empty': 'The submitted file is empty.', 'invalid': 'No file was submitted. Check the encoding type on the form.', 'max_length': '', 'missing': 'No file was submitted.'}¶
- clean(data, initial=None)[source]¶
Validate the given value and return its “cleaned” value as an appropriate Python object. Raise ValidationError for any errors.
- class next.forms.base.FloatField(*, max_value=None, min_value=None, step_size=None, **kwargs)[source]¶
- default_error_messages = {'invalid': 'Enter a number.'}¶
- class next.forms.base.HiddenInput(attrs=None)[source]¶
- input_type = 'hidden'¶
- template_name = 'django/forms/widgets/hidden.html'¶
- property media¶
- class next.forms.base.ImageField(*, max_length=None, allow_empty_file=False, **kwargs)[source]¶
- default_validators = [<function validate_image_file_extension>]¶
- default_error_messages = {'invalid_image': 'Upload a valid image. The file you uploaded was either not an image or a corrupted image.'}¶
- class next.forms.base.IntegerField(*, max_value=None, min_value=None, step_size=None, **kwargs)[source]¶
- widget¶
alias of
NumberInput
- default_error_messages = {'invalid': 'Enter a whole number.'}¶
- re_decimal = <SimpleLazyObject: re.compile('\\.0*\\s*$')>¶
- class next.forms.base.MultipleChoiceField(*, choices=(), **kwargs)[source]¶
alias of
MultipleHiddenInput
- widget¶
alias of
SelectMultiple
- default_error_messages = {'invalid_choice': 'Select a valid choice. %(value)s is not one of the available choices.', 'invalid_list': 'Enter a list of values.'}¶
- class next.forms.base.NumberInput(attrs=None)[source]¶
- input_type = 'number'¶
- template_name = 'django/forms/widgets/number.html'¶
- property media¶
- class next.forms.base.PasswordInput(attrs=None, render_value=False)[source]¶
- input_type = 'password'¶
- template_name = 'django/forms/widgets/password.html'¶
- property media¶
- class next.forms.base.RegexField(regex, **kwargs)[source]¶
- __init__(regex, **kwargs)[source]¶
regex can be either a string or a compiled regular expression object.
- property regex¶
- class next.forms.base.Select(attrs=None, choices=())[source]¶
- input_type = 'select'¶
- template_name = 'django/forms/widgets/select.html'¶
- option_template_name = 'django/forms/widgets/select_option.html'¶
- add_id_index = False¶
- checked_attribute = {'selected': True}¶
- option_inherits_attrs = False¶
- use_required_attribute(initial)[source]¶
Don’t render ‘required’ if the first <option> has a value, as that’s invalid HTML.
- property media¶
- class next.forms.base.SelectMultiple(attrs=None, choices=())[source]¶
- allow_multiple_selected = True¶
- value_from_datadict(data, files, name)[source]¶
Given a dictionary of data and this widget’s name, return the value of this widget or None if it’s not provided.
- property media¶
- class next.forms.base.TextInput(attrs=None)[source]¶
- input_type = 'text'¶
- template_name = 'django/forms/widgets/text.html'¶
- property media¶
- class next.forms.base.Textarea(attrs=None)[source]¶
- template_name = 'django/forms/widgets/textarea.html'¶
- property media¶
- class next.forms.base.TimeInput(attrs=None, format=None)[source]¶
- format_key = 'TIME_INPUT_FORMATS'¶
- template_name = 'django/forms/widgets/time.html'¶
- property media¶
- class next.forms.base.TypedChoiceField(*, coerce=<function TypedChoiceField.<lambda>>, empty_value='', **kwargs)[source]¶
- class next.forms.base.URLField(*, assume_scheme=None, **kwargs)[source]¶
-
- default_error_messages = {'invalid': 'Enter a valid URL.'}¶
- default_validators = [<django.core.validators.URLValidator object>]¶
- class next.forms.base.URLInput(attrs=None)[source]¶
- input_type = 'url'¶
- template_name = 'django/forms/widgets/url.html'¶
- property media¶
- exception next.forms.base.ValidationError(message, code=None, params=None)[source]¶
An error while validating data.
- __init__(message, code=None, params=None)[source]¶
The message argument can be a single error, a list of errors, or a dictionary that maps field names to lists of errors. What we define as an “error” can be either a simple string or an instance of ValidationError with its message attribute set, and what we define as list or dictionary can be an actual list or dict or an instance of ValidationError with its error_list or error_dict attribute set.
- property message_dict¶
- property messages¶
- class next.forms.base.Widget(attrs=None)[source]¶
- needs_multipart_form = False¶
- is_localized = False¶
- is_required = False¶
- supports_microseconds = True¶
- use_fieldset = False¶
- value_from_datadict(data, files, name)[source]¶
Given a dictionary of data and this widget’s name, return the value of this widget or None if it’s not provided.
- id_for_label(id_)[source]¶
Return the HTML ID attribute of this Widget for use by a <label>, given the ID of the field. Return an empty string if no ID is available.
This hook is necessary because some widgets have multiple HTML elements and, thus, multiple IDs. In that case, this method should return an ID value that corresponds to the first ID in the widget’s tags.
- property media¶
Markers¶
Dependency injection markers and provider for form parameters.
- class next.forms.markers.DForm[source]¶
Annotation for injecting a form instance by class.
Use as DForm[MyForm] or DForm[“MyForm”].
Dispatch¶
FormActionDispatch and build_form_namespace_for_action are the public members of this module, in the Advanced tier described above.
The underscore-prefixed helpers (_bind_form_for_post, _normalize_handler_response, and similar symbols) are internal hooks and stay off the autodoc surface below.
Treat them as the Internal hooks tier described above.
Shared POST pipeline and helpers for form action dispatch.
- class next.forms.dispatch.FormActionDispatch[source]¶
Shared POST pipeline and response shaping for backends.
- static dispatch(backend: FormActionBackend, request: HttpRequest, action_name: str, meta: dict[str, Any]) HttpResponse[source]¶
Validate the form, run the handler, or re-render errors.
- static form_response(backend: FormActionBackend, request: HttpRequest, action_name: str, form: django_forms.Form | None, template_fragment: str | None) HttpResponse[source]¶
Return full-page HTML for an invalid form submission.
- next.forms.dispatch.build_form_namespace_for_action(action_name: str, request: HttpRequest) types.SimpleNamespace | None[source]¶
Build the SimpleNamespace(form=…) used by {% form %} when lazy.
Manager¶
FormActionManager aggregates backends and exposes URL patterns.
Backends are loaded lazily from NEXT_FRAMEWORK[“DEFAULT_FORM_ACTION_BACKENDS”] on first access. Unlike the components and static managers, this manager does not subscribe to settings_reloaded, because @action registers handlers imperatively at import time. Auto-rebuilding on every reload would drop those registrations and break test runs that rely on session-scoped eager_load_pages. Tests that swap form-action settings must call next.testing.reset_form_actions() explicitly to drop the cached backend list.
- class next.forms.manager.FormActionManager(backends: list[FormActionBackend] | None = None)[source]¶
Holds one or more backends and yields their URL patterns.
- __init__(backends: list[FormActionBackend] | None = None) None[source]¶
Initialise with explicit backends or defer loading to settings.
- register_action(name: str, handler: Callable[..., Any], *, options: FormActionOptions | None = None) None[source]¶
Forward registration to the first backend.
- clear_registries() None[source]¶
Clear every backend that exposes a clear_registry method.
Intended for test isolation. Backends that do not implement clear_registry are skipped silently.
- get_action_url(action_name: str) str[source]¶
Return the reverse URL from the first backend that knows action_name.
- render_form_fragment(request: HttpRequest, action_name: str, form: django_forms.Form | None, template_fragment: str | None = None, *, page_file_path: Path | None = None) str[source]¶
Delegate rendering to the first backend.
- property default_backend: FormActionBackend¶
Return the first configured backend.
Backends¶
Form action backend contract and registry-based default implementation.
- class next.forms.backends.ActionMeta[source]¶
Per-action data stored in the registry backend.
- handler: Callable[..., Any]¶
- class next.forms.backends.FormActionBackend[source]¶
Storage and HTTP dispatch for @action handlers.
- abstractmethod register_action(name: str, handler: Callable[..., Any], *, options: FormActionOptions | None = None) None[source]¶
Record an action from the decorator.
- abstractmethod get_action_url(action_name: str) str[source]¶
Return the reverse URL for action_name.
- abstractmethod dispatch(request: HttpRequest, uid: str) HttpResponse[source]¶
Run the handler for uid.
- class next.forms.backends.FormActionFactory[source]¶
Instantiates backends from merged DEFAULT_FORM_ACTION_BACKENDS entries.
- classmethod create_backend(config: dict[str, Any]) FormActionBackend[source]¶
Return a single backend instance for one settings entry.
The BACKEND key must be present and resolve to a FormActionBackend subclass. The next.E044 system check guarantees the key is present and importable. The next.E045 system check guarantees the imported class subclasses FormActionBackend. Both run before the factory does in production.
- class next.forms.backends.FormActionOptions(form_class: type[django_forms.Form] | Callable[..., type[django_forms.Form]] | None = None, namespace: str | None = None)[source]¶
Options passed to register_action (used by the @action decorator).
form_class may be a Form subclass or a zero-or-more-argument callable that returns one. Callables are resolved per request at dispatch time, enabling factories like ModelAdmin.get_form().
- class next.forms.backends.RegistryFormActionBackend(config: dict[str, Any] | None = None)[source]¶
In-memory actions behind one dispatcher path keyed by UID.
- __init__(config: dict[str, Any] | None = None) None[source]¶
Create an empty action map. config is accepted for factory parity.
- clear_registry() None[source]¶
Drop every registered action and reset the UID index.
Intended for test isolation. Use this to clear actions between independent test sessions that register overlapping names.
- register_action(name: str, handler: Callable[..., Any], *, options: FormActionOptions | None = None) None[source]¶
Store handler, optional form class, and stable uid for the action name.
- generate_urls() list[URLPattern][source]¶
Return one catch-all route when at least one action is registered.
- dispatch(request: HttpRequest, uid: str) HttpResponse[source]¶
Forward a POST request to FormActionDispatch.dispatch.
Action URL Helpers¶
Stable UIDs and related helpers for @action endpoints.
- next.forms.uid.redirect_to_origin(request: HttpRequest, fallback: str = '/') HttpResponseRedirect[source]¶
Redirect back to the page that rendered the form.
- next.forms.uid.validated_next_form_page_path(request: HttpRequest) Path | None[source]¶
Return a trusted page.py path from POST _next_form_page, or None.
Accepts both real page.py files and virtual ones — directories whose only source is a sibling template.djx (the file router already emits routes for those; see FilesystemTreeDispatcher._visit). The downstream renderer (_load_python_module_memo, _load_static_body) tolerates a missing module and falls back to the template, so virtual pages survive the re-render path on form-validation failures.
Formset Helpers¶
Helpers for working with Django formsets in custom UIs.
Frozen Specs¶
Frozen-dataclass specs for rendering Django forms in custom templates.
- class next.forms.serializers.FieldSpec(bound: BoundField, kind: FieldKind, input_type: str, value: Any, selected: tuple[str, ...], is_extra: bool)[source]¶
Render-time descriptor for one BoundField.
- bound: BoundField¶
- kind: FieldKind¶
- value: Any¶
- class next.forms.serializers.FormSectionSpec(label: str, description: str, fields: tuple[FieldSpec, ...])[source]¶
One labelled section in a FormSpec (matches a Django admin fieldset).
- class next.forms.serializers.FormSpec(sections: tuple[FormSectionSpec, ...], non_field_errors: tuple[str, ...])[source]¶
Top-level spec for rendering a form with optional fieldsets.
- sections: tuple[FormSectionSpec, ...]¶
- class next.forms.serializers.FormsetRowSpec(fields: tuple[FieldSpec, ...], hidden_html: str, delete_field: BoundField | None, errors: Mapping[str, list[str]], is_extra: bool)[source]¶
One row inside a FormsetSpec. Render hidden_html with |safe.
- class next.forms.serializers.FormsetSpec(prefix: str, verbose_name_plural: str, management_form: BaseForm, rows: tuple[FormsetRowSpec, ...], non_form_errors: tuple[str, ...], can_delete: bool)[source]¶
Template-friendly view of a Django formset (inline or standalone).
- rows: tuple[FormsetRowSpec, ...]¶
- next.forms.serializers.field_spec(bound: BoundField, *, is_extra: bool = False) FieldSpec[source]¶
Classify a BoundField into a FieldSpec.
- next.forms.serializers.form_spec(form: BaseForm, fieldsets: Sequence[tuple[str | None, Mapping[str, Any]]] | None = None) FormSpec[source]¶
Group form’s fields into sections per Django admin (label, opts).
- next.forms.serializers.formset_spec(formset: BaseFormSet) FormsetSpec[source]¶
Build a FormsetSpec from a Django formset.
Signals¶
See Signals Reference and Form Signals for the form signals (action_registered, action_dispatched, form_validation_failed).
See Also¶
See also
Forms for the topic subtree. Extending for plugging custom backends. Testing for helpers used when asserting handlers. Action Dispatch for the dispatch pipeline.