1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Django 管理画面でのカスタムフィルター admin.SimpleListFilter

Last updated at Posted at 2022-07-02

環境

Windows 11 Home
Python 3.10.2
Django 4.0.2
venv利用あり

背景

管理画面において、フィルターの名称を変えたりカスタマイズしたフィルターを使用したかった。
例えばBool値のフィルタにおいて、「はい」「いいえ」だけでなく、データ登録されていないものを抽出するために
「はい か いいえ=登録あり」「はいでもいいえでもない=登録なし」といったものを用意したかった。

models.py

mysite\models.py
from django.db import models

class TestModel(models.Model):
    class Meta:
        verbose_name = 'テストモデル'
        verbose_name_plural = 'テストモデル'

    columnA = models.CharField(max_length=30, unique=False, primary_key=True)
    columnB = models.EmailField(blank=True, default="")
    columnC = models.BooleanField(blank=True, null=True)
    columnD = models.CharField(max_length=15, blank=True, default="")
    columnE = models.CharField(max_length=15, blank=True, default="")

admin.py

mysite\admin.py
from django.contrib import admin
from .models import TestModel

class TestProxy(TestModel):
    def __str__(self):
        return "TestProxy"

    class Meta:
        verbose_name = ('00_テストモデル')
        verbose_name_plural = ('00_テストモデル')
        
@admin.register(TestProxy)
class TestAdmin(admin.ModelAdmin):
    ordering = ['columnA']
    list_display = ['columnA', 'columnB', 'columnC','columnD','columnE',]
    list_filter = ["columnC", "columnD"]

データ登録

フィルター動作確認のため適当に管理画面から値を入力する。
image.png

list_filter を設定しているためデフォルトの画面右側にフィルタが表示される。

名前の変更

例えば"columnCで絞り込む"というデフォルトのフィルタで表示される「はい」「いいえ」という文言がわかりにくいと思ったら、
名前を変更することができる。
ここでは「はい」を「有効」、「いいえ」を「無効」にする。

mysite\admin.py

class BoolFilter(admin.SimpleListFilter):
    title = 'columnC、Bool名前変更フィルタ'
    parameter_name = 'columnC'

    def lookups(self, request, model_admin):
        return (
            ('True', '有効'),
            ('False', '無効')
        )

    def queryset(self, request, queryset):
        if self.value() == 'True':
            return queryset.filter(columnC=True)
        elif self.value() == 'False':
            return queryset.filter(columnC=False)
        else:
            return queryset.all()
     
    list_filter = [BoolFilter]

ここで注意してほしいのが

    list_filter = ["BoolFilter"]

としてしまうとエラーになる。カラム名ではなくCLASS名を記載するのでダブルクォーテーションは不要。2時間ハマった。
django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:
<class 'myApp.admin.TestAdmin'>: (admin.E116) The value of 'list_filter[1]' refers to 'BoolFilter', which does not refer to a Field.
image.png

正しく記載をするとフィルタに今回追加したフィルタが追加された。機能は「columnC で絞り込む」と全く同じだが、「有効」「無効」としたことでより機能が明確になった。
image.png

カスタムフィルタ

「はい か いいえ=登録あり」「はいでもいいえでもない=登録なし」といったものを用意する。

mysite\admin.py

class CharFilter(admin.SimpleListFilter):
    title = 'columnD、登録有無フィルタ'
    parameter_name = 'columnD'

    def lookups(self, request, model_admin):
        return (
            ('True', '登録あり'),
            ('False', '登録なし')
        )

    def queryset(self, request, queryset):
        if self.value() == 'True':
            return queryset.exclude(columnD__exact="")
        elif self.value() == 'False':
            return queryset.filter(columnD="")
        else:
            return queryset.all()
     
    list_filter = [CharFilter]

新たにカスタムフィルタが追加された。
image.png

実際にボタンを押して動作を確認してみる。
COLUMND列に注目してほしい。まずは「登録あり」
image.png

次は「登録なし」
image.png

ちゃんと動作している。ここで注意があって

    list_filter = ["columnD", CharFilter]

のように同じカラムをlist_filterに追加するとカスタムフィルターが機能しない。
(CharFilterはparameter_name = 'columnD'を指定している)

カスタムフィルタ2

BoolFilterを改良して「有効」「無効」「設定済み(有効か無効)」「未設定(null)」にする。

mysite\admin.py

class BoolFilter(admin.SimpleListFilter):
    title = 'columnC、Bool名前変更フィルタ'
    parameter_name = 'columnC'

    def lookups(self, request, model_admin):
        return (
            ('True', '有効'),
            ('False', '無効'),
            ('Both', '設定済み'),
            ('None', '未設定'),
        )

    def queryset(self, request, queryset):
        if self.value() == 'True':
            return queryset.filter(columnC=True)
        elif self.value() == 'False':
            return queryset.filter(columnC=False)
        elif self.value() == 'Both':
            return queryset.exclude(columnC__exact="")
        elif self.value() == 'None':
            return queryset.filter(columnC=None)
        else:
            return queryset.all()
     
    list_filter = [BoolFilter]

columnCをnullのデータを追加しておく。
image.png

有効
image.png
無効
image.png
設定済み
image.png
未設定
image.png

正しく動作しているようだ。

以上

参考

[Django]管理者サイトの一覧のフィルタを追加する

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?