ReverseRelationAdminMixin¶
- class django_admin_reversefields.mixins.ReverseRelationAdminMixin[source]¶
Bases:
objectMixin to expose reverse ForeignKey bindings on admin forms.
Add this mixin to a Django admin class and declare one or more virtual fields in
reverse_relations. Each virtual field renders a form control that operates on objects ofReverseRelationConfig.modelby updating itsfk_fieldto point at the current admin instance.- The mixin ensures:
The virtual fields appear in
fieldsetswithout causing Django to raise unknown-field errors during form construction.Querysets are filtered per request/object via
limit_choices_toand can be ordered or customised with widgets.Initial selections reflect the current reverse bindings for the object under edit.
Permission gating (optional) can hide/disable fields at render-time and block unauthorized selections during validation.
On save, only authorized fields are persisted and the reverse ForeignKey(s) are synchronized to match the submitted values (unbinding anything deselected).
- reverse_relations¶
Mapping of virtual field name to configuration. The keys here should be used inside the admin’s
fieldsetslike any normal field.- Type:
dict[str, ReverseRelationConfig]
- reverse_relations_atomic¶
When True (default), all reverse relation updates performed during a form save are executed inside a single
transaction.atomic()block. Within each configured field, unbinds are applied before binds to reduce transient uniqueness conflicts. Any database error will roll back the entire set of updates so no partial state is persisted. Set to False to disable transactional behavior.- Type:
bool
- reverse_permissions_enabled¶
When True, require permission to modify reverse fields.
- Type:
bool
- reverse_permission_policy¶
Optional global policy (callable or object with has_perm) used before the default change_<model> check. Per-field config.permission still takes precedence over this.
- Type:
Optional[ReversePermissionPolicy | object]
- reverse_permission_mode¶
Behavior when user lacks permission on the reverse model for a field: - “disable”: render field disabled (read-only) and ignore posted changes - “hide”: remove field from the form
- Type:
str
- Usage:
>>> class MyAdmin(ReverseRelationAdminMixin, ModelAdmin): ... reverse_relations = { ... "site_binding": ReverseRelationConfig( ... model=Site, ... fk_field="meraki", ... ordering=("displayName",), ... ) ... }
- reverse_render_uses_field_policy: bool = False¶
If True, the render gate consults per-field/global policies via
has_reverse_change_permission()(withselection=None) instead of the base permission check. This lets per-field policies affect visibility and editability before any selection exists. Default False preserves the global/base-only render behaviour.
- has_reverse_change_permission(request: HttpRequest, obj: Model | None, config: ReverseRelationConfig, selection: Any | None = None) bool[source]¶
Check if the user may change the reverse model for this field.
By default, requires the global
changepermission on the reverse model. Overrides evaluate in order of precedence: per-field policies onReverseRelationConfig.permission, thenreverse_permission_policyon the admin, followed by this fallback method. Override to enforce object-level checks or alternative permission codenames.- Parameters:
request (HttpRequest) – Current request (for
user).obj (models.Model | None) – The parent instance being edited.
config (ReverseRelationConfig) – Field configuration.
selection (Any) – Current selection, if applicable.
- Returns:
True if changes are allowed.
- Return type:
bool
- get_reverse_relations() dict[str, ReverseRelationConfig][source]¶
Return the configured reverse relations for this admin.
- Returns:
Mapping of virtual field names to their configuration.
- Return type:
dict[str, ReverseRelationConfig]
- get_fields(request, obj=None)[source]¶
Ensure virtual reverse field names are part of the rendered fields.
When an admin does not declare
fieldsets(and does not supplyfieldsexplicitly), Django renders all form fields returned byget_fields. This override appends the virtual reverse field names so templates include them. The baseget_formimplementation receives the same list and ourget_formoverride will strip virtual names before building the base form to avoid unknown-field errors.
- get_form(request: HttpRequest, obj=None, **kwargs)[source]¶
Create a ModelForm class with injected reverse-relation fields.
This method filters out the virtual reverse field names from the
fieldsargument (which Django constructs fromfieldsets), then delegates to the parentget_form. After the base form class is created, it dynamically injects the reverse fields and wires up their querysets and initial values.- Parameters:
request (HttpRequest) – The current request.
obj (models.Model | None) – The instance being edited, if any.
**kwargs – Additional arguments passed to the base implementation.
- Returns:
A dynamically derived form class containing the configured reverse relation fields.
- Return type:
type[forms.ModelForm]
- save_model(request: HttpRequest, obj, form, change)[source]¶
Save model and apply any deferred reverse relation updates.
This ensures reverse relations are synchronized even when the form save was called with
commit=False.- Parameters:
request (HttpRequest) – The current request.
obj (models.Model) – The model instance being saved.
form (forms.ModelForm) – The bound form.
change (bool) – True if updating an existing object, False if adding.