Skip to content

Commit fe32832

Browse files
committed
Add MultiSelectRelatedFieldListFilter
1 parent bd85e70 commit fe32832

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "django-admin-multi-select-filter"
3-
version = "1.1.0"
3+
version = "1.2.0"
44
description = "Django admin filter for multiple select"
55
readme = "README.md"
66
authors = [{ name = "Job Doesburg", email = "[email protected]" }]

src/django_admin_multi_select_filter/filters.py

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,12 @@ def __init__(self, field, request, params, model, model_admin, field_path):
2020
# Obey parent ModelAdmin queryset when deciding which options to show
2121
if model == parent_model:
2222
queryset = model_admin.get_queryset(request)
23-
self.lookup_choices = (
24-
queryset.distinct().order_by(field.name).values_list(field.name, flat=True)
25-
)
2623
else:
2724
queryset = parent_model._default_manager.all()
28-
self.lookup_choices = queryset.distinct()
29-
25+
self.lookup_choices = (
26+
queryset.distinct().order_by(field.name).values_list(field.name, flat=True)
27+
)
28+
3029
def expected_parameters(self):
3130
return [self.lookup_kwarg, self.lookup_kwarg_isnull]
3231

@@ -76,3 +75,51 @@ def choices(self, changelist):
7675
),
7776
"display": self.empty_value_display,
7877
}
78+
79+
80+
class MultiSelectRelatedFieldListFilter(admin.RelatedFieldListFilter):
81+
def __init__(self, field, request, params, model, model_admin, field_path):
82+
super().__init__(field, request, params, model, model_admin, field_path)
83+
self.lookup_kwarg = "%s__%s__in" % (field_path, field.target_field.name)
84+
self.lookup_kwarg_isnull = "%s__isnull" % field_path
85+
values = params.get(self.lookup_kwarg, [])
86+
self.lookup_val = values.split(",") if values else []
87+
self.lookup_choices = self.field_choices(field, request, model_admin)
88+
89+
def choices(self, changelist):
90+
yield {
91+
"selected": self.lookup_val is None and not self.lookup_val_isnull,
92+
"query_string": changelist.get_query_string(
93+
remove=[self.lookup_kwarg, self.lookup_kwarg_isnull]
94+
),
95+
"display": _("All"),
96+
}
97+
98+
for pk_val, val in self.lookup_choices:
99+
if val is None:
100+
self.include_empty_choice = True
101+
continue
102+
val = str(val)
103+
104+
if str(pk_val) in self.lookup_val:
105+
values = [str(v) for v in self.lookup_val if str(v) != str(pk_val)]
106+
else:
107+
values = self.lookup_val + [str(pk_val)]
108+
109+
yield {
110+
"selected": self.lookup_val is not None
111+
and str(pk_val) in self.lookup_val,
112+
"query_string": changelist.get_query_string(
113+
{self.lookup_kwarg: ",".join(values)}, [self.lookup_kwarg_isnull]
114+
),
115+
"display": val,
116+
}
117+
empty_title = self.empty_value_display
118+
if self.include_empty_choice:
119+
yield {
120+
"selected": bool(self.lookup_val_isnull),
121+
"query_string": changelist.get_query_string(
122+
{self.lookup_kwarg_isnull: "True"}, [self.lookup_kwarg]
123+
),
124+
"display": empty_title,
125+
}

0 commit comments

Comments
 (0)