Refactor UserUserGroupForm to use a reusable UserSearchSelectMultipleWidget for improved user selection and search functionality

This commit is contained in:
Ross
2025-11-13 21:48:58 +00:00
parent 345977e2ef
commit a70354c18d
+13 -14
View File
@@ -556,20 +556,16 @@ class UserUserGroupModelChoiceField(ModelMultipleChoiceField):
return f"{obj.username} ({obj.userprofile.grade}) [{obj.email}]"
class UserUserGroupForm(ModelForm):
class UserSearchSelectMultiple(object):
"""
Lightweight widget renderer for a searchable multi-user selector.
Renders a hidden <select multiple> containing selected user ids and
a search box with results. Uses a small inline script to fetch
results from the `generic:user_search_widget` endpoint and add/remove
users from the selection.
This keeps implementation simple and avoids external JS dependencies.
class UserSearchSelectMultipleWidget:
"""Reusable lightweight widget renderer for a searchable multi-user selector.
Usage: instantiate with (name, value) where value is an iterable of user ids
and call .render() to get the HTML fragment. This mirrors the previous
nested widget but is available module-wide for reuse.
"""
def __init__(self, name, value):
self.name = name
# value is a list of selected user ids
self.value = value or []
def render(self):
@@ -578,13 +574,11 @@ class UserUserGroupForm(ModelForm):
results_id = f"user_search_results_{self.name}"
selected_list_id = f"selected_users_{self.name}"
# Build initial options for selected users
users = User.objects.filter(pk__in=self.value) if self.value else []
options_html = ""
selected_html = ""
for u in users:
options_html += f'<option value="{u.pk}" selected>{u.get_full_name() or u.username} - {u.email}</option>'
# include grade display in the selected list if available
grade_text = ""
try:
up = getattr(u, "userprofile", None)
@@ -605,10 +599,10 @@ class UserUserGroupForm(ModelForm):
url = reverse("generic:user_search_widget")
# Build a small grade filter select
grades_options = '<option value="">All grades</option>'
try:
from generic.models import UserGrades
grades_qs = UserGrades.objects.all()
for g in grades_qs:
grades_options += f'<option value="{g.pk}">{g.name}</option>'
@@ -776,6 +770,11 @@ class UserUserGroupForm(ModelForm):
return mark_safe(html)
class UserUserGroupForm(ModelForm):
# Use module-level UserSearchSelectMultipleWidget for rendering the users field
users = UserUserGroupModelChoiceField(
required=False,
queryset=User.objects.all(),
@@ -808,7 +807,7 @@ class UserUserGroupForm(ModelForm):
# store attrs so template helpers can inspect them
self.attrs = attrs or {}
value = value or []
widget = UserUserGroupForm.UserSearchSelectMultiple(name, value)
widget = UserSearchSelectMultipleWidget(name, value)
return widget.render()
def value_from_datadict(self, data, files, name):