是多选django管理过滤器可能..?

时间:2016-09-30 11:07:06

标签: django django-models

假设有一个名为“城市”的模型,并且在管理员端有一个过滤器“city_name”来根据城市名称过滤模型。 默认情况下,django只允许从django admin过滤器中选择一个城市名称。 但是我需要在django admin过滤器中选择多重城市名称。我怎么能这样做。??

3 个答案:

答案 0 :(得分:1)

您可以通过继承django.contrib.admin.SimpleListFilter

来使用Django自定义list_filter

这是一个简单的例子:

from django.contrib import admin

class MultiSelectFilter(admin.SimpleListFilter):
    # Filter title
    title = 'Cities'

    # model field
    parameter_name = 'city_name'

    def lookups(self, request, model_admin):
        # you can modify this part, this is less DRY approach.
        # P.S. assuming city_name is lowercase CharField
        return (
            ('city1,city2,city3', 'City1 or City2 or City3'),
            ('city4,city5,city6', 'City3 or City4 or City6'),
        )

    def queryset(self, request, queryset):

        if self.value() in ('city1,city2,city3', 'city4,city5,city6'):
            # filter if a choice selected
            return queryset.filter(city_name__in=self.value().split(','))
        # default for no filtering
        return queryset

您引用了文档here

答案 1 :(得分:0)

You can use this new tool django-admin-multiple-choice-list-filter.

答案 2 :(得分:0)

您可以使用AllValuesFieldListFilter内置的经过稍微修改的版本:

from django.contrib import admin
from django.contrib.admin.utils import reverse_field_path
from django.utils.translation import gettext_lazy as _

class MultiSelectFieldListFilter(admin.FieldListFilter):
    def __init__(self, field, request, params, model, model_admin, field_path):
        self.lookup_kwarg = field_path + '__in'
        self.lookup_kwarg_isnull = field_path + '__isnull'

        super().__init__(field, request, params, model, model_admin, field_path)

        self.lookup_val = self.used_parameters.get(self.lookup_kwarg, [])
        if len(self.lookup_val) == 1 and self.lookup_val[0] == '':
            self.lookup_val = []
        self.lookup_val_isnull = self.used_parameters.get(self.lookup_kwarg_isnull)

        self.empty_value_display = model_admin.get_empty_value_display()
        parent_model, reverse_path = reverse_field_path(model, field_path)
        # Obey parent ModelAdmin queryset when deciding which options to show
        if model == parent_model:
            queryset = model_admin.get_queryset(request)
        else:
            queryset = parent_model._default_manager.all()
        self.lookup_choices = queryset.distinct().order_by(field.name).values_list(field.name, flat=True)

    def expected_parameters(self):
        return [self.lookup_kwarg, self.lookup_kwarg_isnull]

    def choices(self, changelist):
        yield {
            'selected': not self.lookup_val and self.lookup_val_isnull is None,
            'query_string': changelist.get_query_string(remove=[self.lookup_kwarg, self.lookup_kwarg_isnull]),
            'display': _('All'),
        }
        include_none = False
        for val in self.lookup_choices:
            if val is None:
                include_none = True
                continue
            val = str(val)

            if val in self.lookup_val:
                values = [v for v in self.lookup_val if v != val]
            else:
                values = self.lookup_val + [ val ]

            if values:
                yield {
                    'selected': val in self.lookup_val,
                    'query_string': changelist.get_query_string({self.lookup_kwarg: ','.join(values)}, [self.lookup_kwarg_isnull]),
                    'display': val,
                }
            else:
                yield {
                    'selected': val in self.lookup_val,
                    'query_string': changelist.get_query_string(remove=[self.lookup_kwarg]),
                    'display': val,
                }

        if include_none:
            yield {
                'selected': bool(self.lookup_val_isnull),
                'query_string': changelist.get_query_string({self.lookup_kwarg_isnull: 'True'}, [self.lookup_kwarg]),
                'display': self.empty_value_display,
            }

在值中转义逗号也应实现,但我不需要它。

(经过Django 2.2.5测试)