環境
Windows 11 Home
Python 3.10.2
Django 4.0.2
venv利用あり
背景
管理画面において、フィルターの名称を変えたりカスタマイズしたフィルターを使用したかった。
例えばBool値のフィルタにおいて、「はい」「いいえ」だけでなく、データ登録されていないものを抽出するために
「はい か いいえ=登録あり」「はいでもいいえでもない=登録なし」といったものを用意したかった。
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
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"]
データ登録
list_filter
を設定しているためデフォルトの画面右側にフィルタが表示される。
名前の変更
例えば"columnCで絞り込む"というデフォルトのフィルタで表示される「はい」「いいえ」という文言がわかりにくいと思ったら、
名前を変更することができる。
ここでは「はい」を「有効」、「いいえ」を「無効」にする。
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.
正しく記載をするとフィルタに今回追加したフィルタが追加された。機能は「columnC で絞り込む」と全く同じだが、「有効」「無効」としたことでより機能が明確になった。
カスタムフィルタ
「はい か いいえ=登録あり」「はいでもいいえでもない=登録なし」といったものを用意する。
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]
実際にボタンを押して動作を確認してみる。
COLUMND列に注目してほしい。まずは「登録あり」
ちゃんと動作している。ここで注意があって
list_filter = ["columnD", CharFilter]
のように同じカラムをlist_filter
に追加するとカスタムフィルターが機能しない。
(CharFilterはparameter_name = 'columnD'
を指定している)
カスタムフィルタ2
BoolFilter
を改良して「有効」「無効」「設定済み(有効か無効)」「未設定(null)」にする。
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]
正しく動作しているようだ。
以上