ModelAdmin リストフィルタ

ModelAdmin クラスは、以下のスクリーンショットのように、admin アプリケーションの変更一覧ページの右サイドバーに表示されるリストフィルタを定義できます:

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

フィールドごとのフィルタリングを有効にするには、ModelAdmin.list_filter を要素のリストまたはタプルに設定し、各要素が以下のいずれかのタイプでなければなりません:

  • フィールド名。

  • django.contrib.admin.SimpleListFilter のサブクラス。

  • フィールド名と django.contrib.admin.FieldListFilter のサブクラスを含む 2値タプル。

list_filter を定義するための各オプションについては、以下の例を参照してください。

フィールド名を使用する

最も簡単なオプションは、モデルから必須のフィールド名を指定することです。

指定するフィールドは BooleanField, CharField, DateField, DateTimeField, IntegerField, ForeignKey または ManyToManyField のいずれかでなければなりません:

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 を使用する

最後に、フィールドに使用する明示的なフィルタタイプを指定したい場合は、2値タプルとして 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),
    ]

authorUser モデルの 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) を参照してください。

ファセット (Facet)

New in Django 5.0.

デフォルトでは、ファセット (facet) と呼ばれる各フィルタのカウントは、admin UIからトグルで表示できます。これらのカウントは現在適用されているフィルタに応じて更新されます。詳細は ModelAdmin.show_facets を参照してください。

Back to Top