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 OneToOneField relations as single-select fields (multiple=False).

  • If the reverse column is null=False, enforce required=True on 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 executionlimit_choices_to runs 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() or prefetch_related() inside the limiter to control query counts.