ModelAdmin 列表过滤器

ModelAdmin 类可以定义出现在管理员的更改列表页面右侧边栏上的列表过滤器,如下面的截图所示:

../../../../_images/list_filter.png

要启用按字段过滤,将 ModelAdmin.list_filter 设置为一个元素列表或元组,其中每个元素都是以下类型之一:

  • 一个字段名称。
  • django.contrib.admin.SimpleListFilter 的子类。
  • 一个包含字段名称和 django.contrib.admin.FieldListFilter 子类的 2 元组。

请查看以下示例,讨论了定义 list_filter 的每个选项。

使用字段名称

最简单的选项是指定你的模型中需要的字段名称。

每个指定的字段应该是 BooleanFieldCharFieldDateFieldDateTimeFieldIntegerFieldForeignKeyManyToManyField 中的一个,例如:

  1. class PersonAdmin(admin.ModelAdmin):
  2. list_filter = ["is_staff", "company"]

list_filter 中的字段名也可以使用 __ 查找来跨越关系,例如:

  1. class PersonAdmin(admin.UserAdmin):
  2. list_filter = ["company__name"]

使用 SimpleListFilter

对于自定义过滤,你可以通过子类化 django.contrib.admin.SimpleListFilter 来定义自己的列表过滤器。你需要提供 titleparameter_name 属性,并重写 lookupsqueryset 方法,例如:

  1. from datetime import date
  2. from django.contrib import admin
  3. from django.utils.translation import gettext_lazy as _
  4. class DecadeBornListFilter(admin.SimpleListFilter):
  5. # Human-readable title which will be displayed in the
  6. # right admin sidebar just above the filter options.
  7. title = _("decade born")
  8. # Parameter for the filter that will be used in the URL query.
  9. parameter_name = "decade"
  10. def lookups(self, request, model_admin):
  11. """
  12. Returns a list of tuples. The first element in each
  13. tuple is the coded value for the option that will
  14. appear in the URL query. The second element is the
  15. human-readable name for the option that will appear
  16. in the right sidebar.
  17. """
  18. return [
  19. ("80s", _("in the eighties")),
  20. ("90s", _("in the nineties")),
  21. ]
  22. def queryset(self, request, queryset):
  23. """
  24. Returns the filtered queryset based on the value
  25. provided in the query string and retrievable via
  26. `self.value()`.
  27. """
  28. # Compare the requested value (either '80s' or '90s')
  29. # to decide how to filter the queryset.
  30. if self.value() == "80s":
  31. return queryset.filter(
  32. birthday__gte=date(1980, 1, 1),
  33. birthday__lte=date(1989, 12, 31),
  34. )
  35. if self.value() == "90s":
  36. return queryset.filter(
  37. birthday__gte=date(1990, 1, 1),
  38. birthday__lte=date(1999, 12, 31),
  39. )
  40. class PersonAdmin(admin.ModelAdmin):
  41. list_filter = [DecadeBornListFilter]

备注

为方便起见,HttpRequest 对象被传递给 lookupsqueryset 方法,例如:

  1. class AuthDecadeBornListFilter(DecadeBornListFilter):
  2. def lookups(self, request, model_admin):
  3. if request.user.is_superuser:
  4. return super().lookups(request, model_admin)
  5. def queryset(self, request, queryset):
  6. if request.user.is_superuser:
  7. return super().queryset(request, queryset)

另外,为了方便起见,ModelAdmin 对象被传递给 lookups 方法,例如,如果你想根据现有数据进行查找:

  1. class AdvancedDecadeBornListFilter(DecadeBornListFilter):
  2. def lookups(self, request, model_admin):
  3. """
  4. Only show the lookups if there actually is
  5. anyone born in the corresponding decades.
  6. """
  7. qs = model_admin.get_queryset(request)
  8. if qs.filter(
  9. birthday__gte=date(1980, 1, 1),
  10. birthday__lte=date(1989, 12, 31),
  11. ).exists():
  12. yield ("80s", _("in the eighties"))
  13. if qs.filter(
  14. birthday__gte=date(1990, 1, 1),
  15. birthday__lte=date(1999, 12, 31),
  16. ).exists():
  17. yield ("90s", _("in the nineties"))

使用字段名称和显式的 FieldListFilter

最后,如果你希望为一个字段指定明确的过滤器类型,你可以提供一个包含 2 个元素的 list_filter 项,其中第一个元素是字段名称,第二个元素是继承自 django.contrib.admin.FieldListFilter 的类,例如:

  1. class PersonAdmin(admin.ModelAdmin):
  2. list_filter = [
  3. ("is_staff", admin.BooleanFieldListFilter),
  4. ]

这里”is_staff”字段将使用”BooleanFieldListFilter”。在大多数情况下,只指定字段名的字段会自动使用适当的过滤器,但这种格式允许您控制所使用的过滤器。

下面的示例显示了您需要选择使用的可用过滤器类别。

你可以使用 RelatedOnlyFieldListFilter 将相关模型的选择限制在该关系所涉及的对象上:

  1. class BookAdmin(admin.ModelAdmin):
  2. list_filter = [
  3. ("author", admin.RelatedOnlyFieldListFilter),
  4. ]

假设 author 是一个指向 User 模型的 ForeignKey,这将限制 list_filter 的选择只列出写过书的用户,而不是列出所有用户。

你可以使用 EmptyFieldListFilter 来过滤空值,它既可以过滤空字符串也可以过滤空值,这取决于字段允许存储的内容:

  1. class BookAdmin(admin.ModelAdmin):
  2. list_filter = [
  3. ("title", admin.EmptyFieldListFilter),
  4. ]

通过使用 __in 查询,可以过滤一组值中的任何一个。你需要重写 expected_parameters 方法,并指定具有适当字段名称的 lookup_kwargs 属性。默认情况下,查询字符串中的多个值将用逗号分隔,但可以通过 list_separator 属性进行自定义。以下示例显示了使用垂直竖线字符作为分隔符的过滤器:

  1. class FilterWithCustomSeparator(admin.FieldListFilter):
  2. # custom list separator that should be used to separate values.
  3. list_separator = "|"
  4. def __init__(self, field, request, params, model, model_admin, field_path):
  5. self.lookup_kwarg = "%s__in" % field_path
  6. super().__init__(field, request, params, model, model_admin, field_path)
  7. def expected_parameters(self):
  8. return [self.lookup_kwarg]

备注

不支持 GenericForeignKey 字段。

列表过滤器通常只在过滤器具有多个选择时才会出现。过滤器的 has_output() 方法控制它是否出现。

可以指定一个自定义模板来呈现列表过滤器:

  1. class FilterWithCustomTemplate(admin.SimpleListFilter):
  2. template = "custom_template.html"

具体的例子请看 Django 提供的默认模板(admin/filter.html)。