ModelAdmin 列表过滤器

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

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

要激活每个字段的过滤,请将ModelAdmin.list_filter 设置为元素列表或元组,其中每个元素都是以下类型之一

  • 字段名称。

  • django.contrib.admin.SimpleListFilter 的子类。

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

请参阅下面的示例,了解定义 list_filter 的每个选项的讨论。

使用字段名称

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

每个指定的字段应为 BooleanFieldCharFieldDateFieldDateTimeFieldIntegerFieldForeignKeyManyToManyField,例如

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

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

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

使用 SimpleListFilter

对于自定义过滤,您可以通过继承 django.contrib.admin.SimpleListFilter 来定义自己的列表过滤器。您需要提供 titleparameter_name 属性,并覆盖 lookupsqueryset 方法,例如

from datetime import date

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


class DecadeBornListFilter(admin.SimpleListFilter):
    # Human-readable title which will be displayed in the
    # right admin sidebar just above the filter options.
    title = _("decade born")

    # Parameter for the filter that will be used in the URL query.
    parameter_name = "decade"

    def lookups(self, request, model_admin):
        """
        Returns a list of tuples. The first element in each
        tuple is the coded value for the option that will
        appear in the URL query. The second element is the
        human-readable name for the option that will appear
        in the right sidebar.
        """
        return [
            ("80s", _("in the eighties")),
            ("90s", _("in the nineties")),
        ]

    def queryset(self, request, queryset):
        """
        Returns the filtered queryset based on the value
        provided in the query string and retrievable via
        `self.value()`.
        """
        # Compare the requested value (either '80s' or '90s')
        # to decide how to filter the queryset.
        if self.value() == "80s":
            return queryset.filter(
                birthday__gte=date(1980, 1, 1),
                birthday__lte=date(1989, 12, 31),
            )
        if self.value() == "90s":
            return queryset.filter(
                birthday__gte=date(1990, 1, 1),
                birthday__lte=date(1999, 12, 31),
            )


class PersonAdmin(admin.ModelAdmin):
    list_filter = [DecadeBornListFilter]

注意

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

class AuthDecadeBornListFilter(DecadeBornListFilter):
    def lookups(self, request, model_admin):
        if request.user.is_superuser:
            return super().lookups(request, model_admin)

    def queryset(self, request, queryset):
        if request.user.is_superuser:
            return super().queryset(request, queryset)

同样为了方便起见,ModelAdmin 对象被传递给 lookups 方法,例如,如果您想根据可用数据来设定查找范围

class AdvancedDecadeBornListFilter(DecadeBornListFilter):
    def lookups(self, request, model_admin):
        """
        Only show the lookups if there actually is
        anyone born in the corresponding decades.
        """
        qs = model_admin.get_queryset(request)
        if qs.filter(
            birthday__gte=date(1980, 1, 1),
            birthday__lte=date(1989, 12, 31),
        ).exists():
            yield ("80s", _("in the eighties"))
        if qs.filter(
            birthday__gte=date(1990, 1, 1),
            birthday__lte=date(1999, 12, 31),
        ).exists():
            yield ("90s", _("in the nineties"))

使用字段名称和显式的 FieldListFilter

最后,如果您希望指定一个显式的过滤器类型与字段一起使用,您可以提供一个 list_filter 项目作为 2 元组,其中第一个元素是字段名称,第二个元素是从 django.contrib.admin.FieldListFilter 继承的类,例如

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

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

以下示例显示了您需要选择使用哪些可用的过滤器类。

您可以使用 RelatedOnlyFieldListFilter 将相关模型的选择限制为该关系中涉及的对象

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

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

您可以使用 EmptyFieldListFilter 过滤空值,它可以根据字段允许存储的内容过滤空字符串和空值

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

通过使用 __in 查找定义过滤器,可以过滤任何一组值。您需要覆盖 expected_parameters 方法,并使用合适的字段名称指定 lookup_kwargs 属性。默认情况下,查询字符串中的多个值将用逗号分隔,但这可以通过 list_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]

注意

GenericForeignKey 字段不受支持。

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

可以指定自定义模板来渲染列表过滤器

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

请参阅 Django 提供的默认模板(admin/filter.html)以获取具体示例。

方面

Django 5.0 中的新增功能。

默认情况下,每个过滤器的计数(称为方面)可以通过管理员 UI 中的切换显示。这些计数将根据当前应用的过滤器进行更新。有关更多详细信息,请参阅ModelAdmin.show_facets

返回顶部