こんにちは、かつコーチです。
Djangoの大きな魅力のひとつが、管理画面(Admin)が標準で用意されている点です。
とはいえ、デフォルトのままだと使いづらい部分も多く、実務ではほぼ必ずカスタマイズします。
今回はDjango Adminの基本から、よく使うカスタマイズ方法までまとめて解説します。
Django Adminとは
コードを書かずにCRUD画面が手に入る仕組み
Django Adminとは、モデルを登録するだけで、データの一覧・追加・編集・削除ができる管理画面が自動生成される機能です。
django-admin startprojectで作成したプロジェクトには、最初からdjango.contrib.adminが組み込まれています。
/admin/にアクセスすると、ログイン画面が表示されるはずです。
モデルをAdminに登録する最小手順
Adminにモデルを表示させるには、admin.pyに登録するだけです。
# blog/admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
これだけで、Postモデルの一覧・追加・編集画面が使えるようになります。
一覧画面をカスタマイズする
list_displayで表示項目を増やす
デフォルトの一覧画面は、モデル名がそのまま表示されるだけで情報が少なすぎます。
ModelAdminクラスを継承して、表示項目をカスタマイズしましょう。
# blog/admin.py
from django.contrib import admin
from .models import Post
class PostAdmin(admin.ModelAdmin):
list_display = ["title", "author", "created_at", "is_published"]
list_filter = ["is_published", "created_at"]
search_fields = ["title", "content"]
admin.site.register(Post, PostAdmin)
list_display:一覧に表示するカラムを指定するlist_filter:画面右側に絞り込み用のフィルタを表示するsearch_fields:検索ボックスで対象にするフィールドを指定する
この3つを設定するだけで、体感の使いやすさがかなり変わります。
list_editableで一覧からその場編集する
公開・非公開のフラグのような項目は、詳細画面を開かずに一覧上で直接変更できると便利です。
class PostAdmin(admin.ModelAdmin):
list_display = ["title", "is_published"]
list_editable = ["is_published"]
注意点として、list_editableに指定するフィールドはlist_displayにも含めておく必要があります。
入力フォームをカスタマイズする
fieldsとfieldsetsでフォームの構成を整える
登録・編集フォームに表示する項目や順序を制御するにはfieldsを使います。
class PostAdmin(admin.ModelAdmin):
fields = ["title", "content", "author"]
さらにセクションごとにグループ化したい場合はfieldsetsを使います。
class PostAdmin(admin.ModelAdmin):
fieldsets = (
("基本情報", {"fields": ("title", "author")}),
("本文", {"fields": ("content",)}),
("公開設定", {"fields": ("is_published", "published_at")}),
)
項目数が多いモデルほど、fieldsetsでグループ分けしておくと入力担当者にとって見やすい画面になります。
readonly_fieldsで編集不可の項目を作る
作成日時のような、自動で設定されて手動編集されるべきでない項目は、readonly_fieldsにしておきます。
class PostAdmin(admin.ModelAdmin):
readonly_fields = ["created_at", "updated_at"]
関連モデルをまとめて編集する:インライン
TabularInlineで親子関係を1画面にまとめる
Postに対するCommentのように、1対多の関連がある場合、親モデルの編集画面に子モデルの一覧を埋め込むと効率的です。
class CommentInline(admin.TabularInline):
model = Comment
extra = 1
class PostAdmin(admin.ModelAdmin):
inlines = [CommentInline]
extraは、初期状態で表示する空の入力フォームの行数です。
コメントを都度別画面で編集する必要がなくなり、投稿とコメントを同時に管理できるようになります。
つまずきやすいポイント
大量データで一覧表示が極端に遅くなる
❌ Before:関連モデルをそのままlist_displayに含めてしまう
class PostAdmin(admin.ModelAdmin):
list_display = ["title", "author", "comment_count"]
def comment_count(self, obj):
return obj.comments.count()
一覧に表示される行数分だけ、comments.count()が毎回実行されてしまいます。
筆者は実際にデータが数千件になった検証環境で、一覧画面の表示に10秒以上かかるようになった経験があります。
原因は、このcomment_countメソッドが1行ごとに個別クエリを発行していたことでした。
✅ After:get_queryset()で事前に集計しておく
from django.db.models import Count
class PostAdmin(admin.ModelAdmin):
list_display = ["title", "author", "comment_count"]
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.annotate(_comment_count=Count("comments"))
def comment_count(self, obj):
return obj._comment_count
comment_count.short_description = "コメント数"
annotate()で集計を事前に一括計算しておくことで、クエリの発行回数を大幅に減らせます。
この考え方は、後述するN+1問題の対策とも共通する重要なポイントです。
まとめ
この記事のポイント
admin.site.register()でモデルを登録するだけでCRUD画面が手に入るlist_display・list_filter・search_fieldsで一覧画面を使いやすくするfieldsetsでフォームの入力項目をグループ化できる- インラインを使うと、関連モデルをまとめて1画面で編集できる
- 一覧に計算結果を表示するときは、クエリの発行回数に注意する
次に読むべき記事
- N+1問題とselect_related・prefetch_relatedでの解決方法
- makemigrations/migrateの基本:モデルをDBに反映する
- カスタムユーザーモデル(AbstractUser)を実装する
タグ: Django, 中級者向け, フレームワーク基礎