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 來篩選空值,它可以根據欄位允許儲存的內容來篩選空字串和 null 值

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 新增功能。

預設情況下,每個篩選器的計數(稱為構面)可以透過管理介面上的切換來顯示。這些計數將根據目前套用的篩選器進行更新。請參閱 ModelAdmin.show_facets 以取得更多詳細資訊。

返回頂部