Caveats¶
This page highlights operational edge-cases and limitations that are easy to overlook while following the happy-path guides (Quickstart, Recipes). Use it alongside Data Integrity & Transactions and Permissions when planning production roll-outs.
ForeignKey requirements¶
Important
Ensure the reverse ForeignKey is nullable whenever
unbinding should be allowed. If the column is
null=False, set required=True on the
ReverseRelationConfig so the form
blocks unbind attempts rather than raising
django.db.IntegrityError.
See also
The persistence order (unbind before bind) is documented in Data Integrity & Transactions.
Transactional behaviour¶
Note
reverse_relations_atomic
defaults to True so every configured binding update runs
inside a single django.db.transaction.atomic() block. Opt-out only when
partial failures are acceptable. Even with atomic updates, concurrent edits on
the same reverse object can still surface database-level uniqueness errors; be
prepared to catch them in custom workflows.
Feature scope¶
Supported relationship types
The mixin targets reverse ForeignKey and OneToOneField bindings. It
does not manage ManyToManyField relations or polymorphic relations
such as GenericForeignKey.
Display customisation¶
The default widgets mirror the Django admin look-and-feel. Override
ReverseRelationConfig.widget to plug in custom widgets (e.g. Unfold, DAL) or
see the Advanced gallery for end-to-end examples. For request-aware
choice limiting, revisit Querysets & Widgets.
For how fields are included in the form and when they are visible vs. disabled, see Rendering & Visibility.
Permission interplay¶
Caution
When reverse_permissions_enabled=True the mixin requires the user to pass
one of the configured policies before persisting changes.
Denied fields are ignored during save (including hidden/disabled fields), so
crafted POSTs cannot sidestep the check. The render-time behaviour is controlled by
reverse_permission_mode
("disable" or "hide"). Refer back to Permissions for the
evaluation flow and error-message precedence.
By default, the render gate consults only a base/global permission. To let
per-field/global policies influence visibility/editability, set
reverse_render_uses_field_policy=True on the admin.
See Rendering & Visibility for the end-to-end visibility and editability flow.
One-to-one specifics¶
Treat
OneToOneFieldrelations as single-select fields (multiple=False).If the reverse column is
null=False, enforcerequired=Trueon the virtual field or make the column nullable.On admin “add” views, limiter callables cannot reference the object being created (because no primary key exists yet). The binding will be applied on the first successful save.
Performance at scale¶
Warning
For parents with very large child sets (tens of thousands of rows), plan for the following:
Initial selection — the mixin loads all currently bound primary keys to seed the form. Multi-select fields can therefore materialise large lists in memory.
Limiter execution —
limit_choices_toruns on every form render. Optimise it with database filtering (.filter(),.exclude()) and avoid iterating in Python. Consider DAL style widgets to reduce the number of loaded options.Widget rendering — if your widget surfaces related-object metadata, combine
select_related()orprefetch_related()inside the limiter to control query counts.