【问题标题】:Is multi choice django admin filters possible..?多选 django 管理过滤器是否可能..?
【发布时间】:2016-09-30 11:07:05
【问题描述】:

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

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    对于那些宁愿使用外部库的人,这些似乎在撰写本文时得到维护(在过去 6 个月内发布):

    django-more-admin-filters:添加了几个过滤器类,包括。多选和下拉过滤器

    django-advanced-filters:添加了一个高级过滤器 mixin,它可以显示一个模式来构建查询,其中包含多个由和/或组合的条件

    与问题无关,但也是一个不错的发现:

    django-admin-autocomplete-list-filter:使自动完成列表过滤成为可能

    【讨论】:

      【解决方案2】:

      您可以使用内置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 测试)

      【讨论】:

        【解决方案3】:

        您可以使用这个新工具django-admin-multiple-choice-list-filter

        【讨论】:

        【解决方案4】:

        你可以通过继承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

        【讨论】:

          猜你喜欢
          • 2015-01-07
          • 2013-07-26
          • 2020-09-15
          • 2020-09-29
          • 1970-01-01
          • 2011-11-14
          • 2017-07-09
          • 2011-11-09
          • 2011-02-24
          相关资源
          最近更新 更多