【Django】Django Adminをカスタマイズして管理画面を使いこなす

Django

こんにちは、かつコーチです。

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_displaylist_filtersearch_fieldsで一覧画面を使いやすくする
  • fieldsetsでフォームの入力項目をグループ化できる
  • インラインを使うと、関連モデルをまとめて1画面で編集できる
  • 一覧に計算結果を表示するときは、クエリの発行回数に注意する

次に読むべき記事

  • N+1問題とselect_related・prefetch_relatedでの解決方法
  • makemigrations/migrateの基本:モデルをDBに反映する
  • カスタムユーザーモデル(AbstractUser)を実装する

タグ: Django, 中級者向け, フレームワーク基礎

タイトルとURLをコピーしました