mirror of https://github.com/django/django.git
Fixed #19721 -- Allowed admin filters to customize the list separator.
This commit is contained in:
parent
2b76f45749
commit
8a4e506760
|
@ -118,6 +118,7 @@ class SimpleListFilter(ListFilter):
|
|||
class FieldListFilter(ListFilter):
|
||||
_field_list_filters = []
|
||||
_take_priority_index = 0
|
||||
list_separator = ','
|
||||
|
||||
def __init__(self, field, request, params, model, model_admin, field_path):
|
||||
self.field = field
|
||||
|
@ -127,7 +128,7 @@ class FieldListFilter(ListFilter):
|
|||
for p in self.expected_parameters():
|
||||
if p in params:
|
||||
value = params.pop(p)
|
||||
self.used_parameters[p] = prepare_lookup_value(p, value)
|
||||
self.used_parameters[p] = prepare_lookup_value(p, value, self.list_separator)
|
||||
|
||||
def has_output(self):
|
||||
return True
|
||||
|
|
|
@ -51,13 +51,13 @@ def lookup_spawns_duplicates(opts, lookup_path):
|
|||
return False
|
||||
|
||||
|
||||
def prepare_lookup_value(key, value):
|
||||
def prepare_lookup_value(key, value, separator=','):
|
||||
"""
|
||||
Return a lookup value prepared to be used in queryset filtering.
|
||||
"""
|
||||
# if key ends with __in, split parameter into separate values
|
||||
if key.endswith('__in'):
|
||||
value = value.split(',')
|
||||
value = value.split(separator)
|
||||
# if key ends with __isnull, special case '' and the string literals 'false' and '0'
|
||||
elif key.endswith('__isnull'):
|
||||
value = value.lower() not in ('', 'false', '0')
|
||||
|
|
|
@ -176,6 +176,25 @@ allows to store::
|
|||
('title', admin.EmptyFieldListFilter),
|
||||
)
|
||||
|
||||
By defining a filter using the ``__in`` lookup, it is possible to filter for
|
||||
any of a group of values. You need to override the ``expected_parameters``
|
||||
method, and the specify the ``lookup_kwargs`` attribute with the appropriate
|
||||
field name. By default, multiple values in the query string will be separated
|
||||
with commas, but this can be customized via the ``list_separator`` attribute.
|
||||
The following example shows such a filter using the vertical-pipe character as
|
||||
the separator::
|
||||
|
||||
class FilterWithCustomSeparator(admin.FieldListFilter):
|
||||
# custom list separator that should be used to separate values.
|
||||
list_separator = '|'
|
||||
|
||||
def __init__(self, field, request, params, model, model_admin, field_path):
|
||||
self.lookup_kwarg = '%s__in' % field_path
|
||||
super().__init__(field, request, params, model, model_admin, field_path)
|
||||
|
||||
def expected_parameters(self):
|
||||
return [self.lookup_kwarg]
|
||||
|
||||
.. note::
|
||||
|
||||
The :class:`~django.contrib.contenttypes.fields.GenericForeignKey` field is
|
||||
|
|
|
@ -54,6 +54,10 @@ Minor features
|
|||
* The admin :ref:`dark mode CSS variables <admin-theming>` are now applied in a
|
||||
separate stylesheet and template block.
|
||||
|
||||
* :ref:`modeladmin-list-filters` providing custom ``FieldListFilter``
|
||||
subclasses can now control the query string value separator when filtering
|
||||
for multiple values using the ``__in`` lookup.
|
||||
|
||||
:mod:`django.contrib.admindocs`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ import unittest
|
|||
|
||||
from django.contrib.admin import (
|
||||
AllValuesFieldListFilter, BooleanFieldListFilter, EmptyFieldListFilter,
|
||||
ModelAdmin, RelatedOnlyFieldListFilter, SimpleListFilter, site,
|
||||
FieldListFilter, ModelAdmin, RelatedOnlyFieldListFilter, SimpleListFilter,
|
||||
site,
|
||||
)
|
||||
from django.contrib.admin.options import IncorrectLookupParameters
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
|
@ -135,6 +136,17 @@ class DepartmentListFilterLookupWithDynamicValue(DecadeListFilterWithTitleAndPar
|
|||
return (('the 80s', "the 1980's"), ('the 90s', "the 1990's"),)
|
||||
|
||||
|
||||
class EmployeeNameCustomDividerFilter(FieldListFilter):
|
||||
list_separator = '|'
|
||||
|
||||
def __init__(self, field, request, params, model, model_admin, field_path):
|
||||
self.lookup_kwarg = '%s__in' % field_path
|
||||
super().__init__(field, request, params, model, model_admin, field_path)
|
||||
|
||||
def expected_parameters(self):
|
||||
return [self.lookup_kwarg]
|
||||
|
||||
|
||||
class CustomUserAdmin(UserAdmin):
|
||||
list_filter = ('books_authored', 'books_contributed')
|
||||
|
||||
|
@ -231,6 +243,12 @@ class EmployeeAdmin(ModelAdmin):
|
|||
list_filter = ['department']
|
||||
|
||||
|
||||
class EmployeeCustomDividerFilterAdmin(EmployeeAdmin):
|
||||
list_filter = [
|
||||
('name', EmployeeNameCustomDividerFilter),
|
||||
]
|
||||
|
||||
|
||||
class DepartmentFilterEmployeeAdmin(EmployeeAdmin):
|
||||
list_filter = [DepartmentListFilterLookupWithNonStringValue]
|
||||
|
||||
|
@ -1547,3 +1565,29 @@ class ListFiltersTests(TestCase):
|
|||
request.user = self.alfred
|
||||
with self.assertRaises(IncorrectLookupParameters):
|
||||
modeladmin.get_changelist_instance(request)
|
||||
|
||||
def test_lookup_using_custom_divider(self):
|
||||
"""
|
||||
Filter __in lookups with a custom divider.
|
||||
"""
|
||||
jane = Employee.objects.create(name='Jane,Green', department=self.design)
|
||||
modeladmin = EmployeeCustomDividerFilterAdmin(Employee, site)
|
||||
employees = [jane, self.jack]
|
||||
|
||||
request = self.request_factory.get(
|
||||
'/', {'name__in': "|".join(e.name for e in employees)}
|
||||
)
|
||||
# test for lookup with custom divider
|
||||
request.user = self.alfred
|
||||
changelist = modeladmin.get_changelist_instance(request)
|
||||
# Make sure the correct queryset is returned
|
||||
queryset = changelist.get_queryset(request)
|
||||
self.assertEqual(list(queryset), employees)
|
||||
|
||||
# test for lookup with comma in the lookup string
|
||||
request = self.request_factory.get('/', {'name': jane.name})
|
||||
request.user = self.alfred
|
||||
changelist = modeladmin.get_changelist_instance(request)
|
||||
# Make sure the correct queryset is returned
|
||||
queryset = changelist.get_queryset(request)
|
||||
self.assertEqual(list(queryset), [jane])
|
||||
|
|
Loading…
Reference in New Issue