Fixes #21763: Replace M2M selection field with separate add/remove fields

This commit is contained in:
Jeremy Stretch
2026-03-27 16:42:43 -04:00
parent bb73601d80
commit f30786d8fe
9 changed files with 103 additions and 28 deletions

View File

@@ -5,6 +5,7 @@ from functools import cached_property
__all__ = (
'FieldSet',
'InlineFields',
'M2MAddRemoveFields',
'ObjectAttribute',
'TabbedGroups',
)
@@ -73,6 +74,21 @@ class TabbedGroups:
]
class M2MAddRemoveFields:
"""
Represents an add/remove field pair for a many-to-many relationship. Rather than rendering
a single multi-select pre-populated with all current values (which can crash the browser for
large datasets), this renders two fields: one for adding new relations and one for removing
existing relations.
Parameters:
name: The name of the M2M field on the model (e.g. 'asns'). The form must define
corresponding 'add_{name}' and 'remove_{name}' fields.
"""
def __init__(self, name):
self.name = name
class ObjectAttribute:
"""
Renders the value for a specific attribute on the form's instance. This may be used to

View File

@@ -1,6 +1,6 @@
from django import template
from utilities.forms.rendering import InlineFields, ObjectAttribute, TabbedGroups
from utilities.forms.rendering import InlineFields, M2MAddRemoveFields, ObjectAttribute, TabbedGroups
__all__ = (
'getfield',
@@ -80,6 +80,13 @@ def render_fieldset(form, fieldset):
('tabs', None, tabs)
)
elif type(item) is M2MAddRemoveFields:
for field_name in (f'add_{item.name}', f'remove_{item.name}'):
if field_name in form.fields:
rows.append(
('field', None, [form[field_name]])
)
elif type(item) is ObjectAttribute:
value = getattr(form.instance, item.name)
label = value._meta.verbose_name if hasattr(value, '_meta') else item.name