---
title: "Django管理画面の設計：admin標準の範囲とModelAdmin・権限の実装"
url: "https://www.issoh.co.jp/tech/details/17078/"
published: 2026-08-28
updated: 2026-09-05
categories: ["開発"]
publisher: "株式会社一創"
---

# Django管理画面の設計：admin標準の範囲とModelAdmin・権限の実装

Djangoの管理画面は、モデルを1行登録するだけで一覧・追加・変更・削除の画面が立ち上がります。ただし直後の画面は、開発者がデータの中身を確かめるためのものです。業務担当者が毎日入力する画面として渡すなら、一覧の列、検索の対象、誰がどの行に触れるか、削除が何を巻き込むかは決め直しが必要です。この記事では、`register`で自動生成される範囲を境界線として引き、立ち上げの手順、ModelAdminの設定、4種のパーミッションとグループ設計、行単位の絞り込み、本番前に塞ぐ仕様上の穴、そして5.2 LTSと6.0・6.1で変わった差分までを、公式ドキュメントの記述と動かせるコードで順に組み立てます。Django本体の位置づけとMVTは[Djangoとは？Python製Webフレームワークの特徴・MVT・始め方を入門解説](https://www.issoh.co.jp/tech/details/3275/)で扱います。

## まとめ：admin標準で足りる範囲と作り直しに切り替える境界

Djangoのadminは、社内の担当者が単票のデータを直す画面としては完成度が高く、同じものを自作する理由はほぼありません。一方、承認の段階を持つ業務や社外の利用者が触る画面には向きません。[公式チュートリアル](https://docs.djangoproject.com/en/5.2/intro/tutorial02/)自身が想定利用者をサイト管理者と明記しており、それを超えた使い方は仕様の外側の運用になります。

`register`だけで手に入るのは、一覧・追加・変更・削除の4画面と管理画面経由の操作履歴です。

最初に効く設定は、一覧の列と検索の指定、関連先の引き方（`list_select_related`と`autocomplete_fields`）の3つになります。

権限は二層です。入室を分けるのが`is_staff`、操作を分けるのが`add`・`change`・`delete`・`view`の4パーミッションになります。アプリ本体側のログイン機能の設計は[Djangoのログイン機能：標準authの範囲とカスタムユーザー・allauth](https://www.issoh.co.jp/tech/details/17099/)で扱っています。

行単位の制御は権限では表現できません。`get_queryset`の上書きで絞ります。

一括削除の既定動作はモデルの`delete()`を呼びません。論理削除や関連ファイル削除を自前で書いているなら、ここが最初の事故になります。

版の選び方も先に置きます。[公式のダウンロードページ](https://www.djangoproject.com/download/)によれば、2026年9月時点の最新は6.1系、長期サポート版は5.2系で、5.2は2028年4月まで延長サポートの対象です。本番はLTSに寄せるのが基本線になります。

採用の線引きは最終章で示します。先に言えば、利用者が社内の数名で、操作が単票の追加と修正に収まり、承認の段取りが要らないならadminのままで足ります。

## Django管理画面を最短で立ち上げる設定とsuperuser作成の手順

何もカスタマイズしない状態で手に入るものを先に確定させます。ここが曖昧だと、標準で動くものを自作したり、無い機能を期待して詰まったりする作業が生まれます。

### INSTALLED\_APPSとURLconfを設定してmigrateを流す手順

`django.contrib.admin`と`django.contrib.auth`が`INSTALLED_APPS`に並び、URLconfに`admin.site.urls`を割り当てた時点で画面自体は存在します。最小の設定はこの2ファイルだけで足ります。

```
# settings.py
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "shop",
]

# urls.py 既定の admin/ ではなく別パスへ割り当てる
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path("back-office/", admin.site.urls),
]
```

設定を書いたら、認証テーブルと既定パーミッションを作り、入室できる利用者を1人用意します。`migrate`を流した時点で、登録済みモデルごとの4パーミッションも同時に生成されます。マイグレーション自体の流れと本番での適用手順は[migrate自体の流れと本番での適用手順](https://www.issoh.co.jp/tech/details/17080/)にまとめました。

```
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver
```

### createsuperuserで入室者を作りis\_staffで入口を絞る

押さえておきたいのが入室条件です。[公式のadminリファレンス](https://docs.djangoproject.com/en/5.2/ref/contrib/admin/)は、既定では管理画面へのログインに`is_staff`属性が真である必要がある、と定めています。入室の可否はモデルごとの権限ではなくフラグ1つで決まる構造になっています。管理画面のビューを守る`staff_member_required`デコレータも、`is_staff`と`is_active`の両方が真のときだけビューを通す実装です。一般会員のアカウントに誤ってこのフラグを立てると、権限が1つも無くてもログイン後の入口までは到達してしまいます。

したがって最初の作業は、権限の設計ではなく`is_staff`を持つアカウントの棚卸しになります。会員登録の処理や外部IDとの連携でこのフラグに触れていないかを、コードを検索して確かめておきます。

### admin.pyでモデルを登録して4画面とLogEntryを確認する

アプリの`admin.py`で`admin.site.register`または`@admin.register`によりモデルを登録すると、登録済みモデル1つにつき、変更一覧（changelist）、追加、変更、削除確認の4画面が生成されます。管理画面から行われた追加・変更・削除は`LogEntry`として記録され、各オブジェクトの「履歴」から追えます。Django 5.0で`AdminSite.get_log_entries()`が加わり、トップ画面の履歴のクエリセットも差し替えられるようになりました。

この履歴には範囲の制約があります。記録されるのは管理画面を経由した操作だけで、ORMやSQLで直接更新した行は残りません。監査ログの代わりに使えるかの判定材料はここです。管理画面以外に更新経路があるなら、履歴はアプリ側で別に持つ設計が要ります。

## ModelAdminを書いて一覧と入力画面を業務の台帳へ寄せる

標準のままでは足りない合図は3つあります。一覧に文字列表現しか出ず毎回変更画面を開いている、外部キーの選択欄が数千件のセレクトボックスになっている、担当外のデータまで一覧に見えている、です。前2つはModelAdminの設定で解け、3つ目は次章のクエリセット上書きが要ります。

### list\_displayとsearch\_fieldsで一覧を検索できる台帳にする

一覧画面の既定は、モデルの`__str__`が返す1列だけです。最初に足す`list_display`は、表示したいフィールド名を並べる指定です。フィールド以外の値はメソッドを定義し、`@admin.display`デコレータで列名や並び替えの対象を指定します。Django 5.0以降はプロパティへの`boolean`属性の指定も通ります。

絞り込みは`list_filter`、キーワード検索は`search_fields`、日付の掘り下げは`date_hierarchy`が担当します。[絞り込みのリファレンス](https://docs.djangoproject.com/en/5.2/ref/contrib/admin/filters/)にあるとおり、`list_filter`には関連先を辿る二重アンダースコアの指定や独自フィルタクラスも渡せる仕組みです。`show_facets`の既定は`ShowFacets.ALLOW`で、URLに`_facets`が付いたときだけ件数が出ます。常時出すなら`ALWAYS`、件数のクエリを避けたい大規模テーブルなら`NEVER`を選びます。

ここまでを1つのクラスにまとめると、次のような形になります。受注テーブルを担当者が毎日触る台帳へ寄せた例です。

```
# shop/admin.py
from django.contrib import admin

from .models import Order


@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    list_display = ("code", "customer", "branch", "status", "total_with_tax", "created_at")
    list_filter = ("status", "branch", "customer__region")
    search_fields = ("code", "customer__name")
    date_hierarchy = "created_at"
    list_select_related = ("customer", "branch")
    autocomplete_fields = ("customer",)
    readonly_fields = ("code", "branch", "created_at")
    list_editable = ("status",)
    list_per_page = 50

    @admin.display(description="税込金額", ordering="total")
    def total_with_tax(self, obj):
        return obj.total * 110 // 100
```

同じ絞り込みを利用者向けの一覧へ出す実装は、[django-filterで一覧検索を実装する｜FilterSet設計とDRF指定の判断](https://www.issoh.co.jp/tech/details/17107/)で扱います。管理画面の`list_filter`とFilterSetは似た記述に見えますが、前者は管理者の画面専用、後者は利用者向けの一覧とAPIに載せるものという住み分けです。

| 設定                    | 既定値   | 変更を検討する場面   |
| --------------------- | ----- | ----------- |
| list\_per\_page       | 100   | 1行が重く描画が遅い  |
| list\_max\_show\_all  | 200   | 全件表示を封じたい   |
| show\_facets          | ALLOW | 件数表示の常時化や停止 |
| list\_select\_related | False | 外部キーを跨ぐ列がある |

左2列は[公式ドキュメントの既定値](https://docs.djangoproject.com/en/5.2/ref/contrib/admin/)です。`list_max_show_all`は「全件表示」リンクを出す上限で、総件数がこの値以下のときだけ出ます。数万件のテーブルでは下げておきます。

### list\_select\_relatedとautocomplete\_fieldsの負荷削減

一覧が遅い原因の大半は行数ではなく、行ごとに走る関連先の取得です。`list_select_related`の既定は`False`ですが、このときDjangoは`list_display`を見て、外部キーの列があれば`select_related()`を呼びます。自動で拾われないのは、メソッド経由で関連先の属性を出す場合と2段以上先を辿る場合で、ここには明示的な指定が必要です。クエリ本数が跳ねる仕組みは[DjangoとRailsにおけるN+1問題解決法の比較と考察](https://www.issoh.co.jp/tech/details/4262/)を先に押さえると理由が読めます。

入力側の負荷は`autocomplete_fields`で下げます。選択欄をSelect2の補完入力に置き換える指定で、候補を非同期で読むためレコード数が多くても追加画面が固まりません。条件は、関連先のModelAdminに`search_fields`があること、利用者が関連オブジェクトの`view`または`change`権限を持つことの2つです。後者は候補一覧経由のデータ露出を防ぐ仕様で、権限設計を後回しにすると「補完が空で返る」形で表面化します。

### readonly\_fieldsとinlines・list\_editableで誤入力を防ぐ

入力画面で先に決めるのは、触らせない列です。`readonly_fields`に登録番号や作成日時、集計値、外部システムの連携キーを入れると、変更画面には表示されたまま編集できなくなります。親子関係のあるデータは`inlines`で同じ画面にまとめ、明細の行数が多いなら表形式の`TabularInline`が読みやすい構成です。

一覧画面で直接編集させる`list_editable`には、対象の列が`list_display`にあることと先頭列にできないという制約があります。ステータス列のような値の限られたフィールドに限って使い、金額や数量には広げないほうが事故が減ります。

## グループと4種のパーミッションを設計して権限を割り当てる作業の手順

管理画面の権限は二層です。分けて見ないと「入れるのに何も見えない」「見えるはずのない行が見える」の原因を切り分けられません。

### add・change・delete・viewをグループへ束ねて付与する作業

`django.contrib.auth`がある状態で`manage.py migrate`を実行すると、各モデルに`add`・`change`・`delete`・`view`の4パーミッションが生成されます。[認証と権限の公式ドキュメント](https://docs.djangoproject.com/en/5.2/topics/auth/default/)にあるとおり、判定に使うコード名は`foo.add_bar`のように、アプリラベルと操作名とモデル名の小文字を連結した形です。`view`は閲覧だけを許す権限で、`change`を持たない担当者にも一覧と詳細を見せたいときに使います。

付与は個人ではなくグループ単位で設計します。Groupは利用者を分類して権限をまとめて与える仕組みで、1人が複数に属せます。崩れにくいのは、モデル単位ではなく業務の役割単位で切る形です。「受注入力」「受注参照」「マスタ管理」の3グループへ必要な権限を割り当てておけば、異動時はグループの差し替えだけで済みます。次のスクリプトを`manage.py shell`に貼れば、役割の定義から付与までを一度に流せます。

```
# manage.py shell に貼って役割ごとの権限をまとめて付与する
from django.contrib.auth.models import Group, Permission

ROLES = {
    "受注入力": ["add_order", "change_order", "view_order"],
    "受注参照": ["view_order"],
    "マスタ管理": ["add_customer", "change_customer", "view_customer"],
}

for name, codenames in ROLES.items():
    group, _ = Group.objects.get_or_create(name=name)
    group.permissions.set(
        Permission.objects.filter(
            content_type__app_label="shop",
            codename__in=codenames,
        )
    )
    print(name, group.permissions.count())
```

権限体系そのものを業務要件に合わせる段階は管理画面の枠を超えます。誰がどの情報に触れてよいかを制度として決めるなら、[会員管理システム開発](https://www.issoh.co.jp/service/system/usersystem/)のように利用者管理を主題に据えた設計から入るほうが手戻りが出ません。

### has\_change\_permissionを上書きして業務条件で判定を変える

判定そのものを変えるなら、ModelAdminの`has_add_permission`・`has_change_permission`・`has_delete_permission`・`has_view_permission`を上書きします。いずれも第2引数に対象オブジェクトを受け取れるため、「締め済みの伝票は変更させない」「自分が起票した申請だけ削除できる」といった条件をPythonで書けます。

`has_view_permission`の既定実装は、`change`か`view`のどちらかがあれば真を返します。`change`だけを与えた利用者にも閲覧が通るのはこのためです。オブジェクトが`None`で呼ばれたときは「この種類を一般に閲覧できるか」の問い合わせで、偽を返すとモデルごと一覧から消えます。メニューから隠すだけならこの分岐を使います。

### get\_querysetを上書きして担当者ごとに行を絞り込む実装

4種のパーミッションはモデル単位でしか効きません。「自分の支店の受注だけ見せる」という行単位の制御は権限では表現できず、`ModelAdmin.get_queryset`を上書きして絞ります。親クラスの戻り値に、リクエストの利用者に紐づく条件でフィルタを重ねる書き方が基本形になります。重ねたQuerySetがいつ評価されるかは、[Django ORMのクエリ設計](https://www.issoh.co.jp/tech/details/17082/)で整理しました。

```
# shop/admin.py 行単位の絞り込みと業務条件での判定
class OrderAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(branch=request.user.profile.branch)

    def has_change_permission(self, request, obj=None):
        if obj is not None and obj.status == "closed":
            return False
        return super().has_change_permission(request, obj)

    def has_delete_permission(self, request, obj=None):
        return request.user.is_superuser
```

見落としやすい穴が2つあります。1つは補完の経路です。`get_queryset`の絞り込みは変更画面にも効きますが、`autocomplete_fields`の補完や`raw_id_fields`の検索窓は別のクエリを通るため、関連先のModelAdmin側にも同じ絞り込みを入れないと候補に名前が見えます。もう1つは絞り込みキーの扱いです。条件に使うフィールドを`readonly_fields`に入れ忘れると、担当者が自分の支店の値を他支店へ書き換え、その行が一覧から消える操作が成立してしまいます。上のコードで`branch`を`readonly_fields`へ入れているのはこのためで、絞り込みキーを編集不可にするところまでを1組で設計します。

## 本番の管理画面として載せる前に塞ぐ仕様上の穴と配信の設定手順

設定が済んでいても、本番前に確認する仕様があります。いずれも公式に明記されているものの、入門記事では触れられない箇所です。

### delete\_selectedがdelete()を呼ばない仕様を3手で回避する

一覧画面の既定アクション「選択された項目の削除」には、[管理アクションの公式ドキュメント](https://docs.djangoproject.com/en/5.2/ref/contrib/admin/actions/)が警告として明記する挙動があります。効率のため`QuerySet.delete()`を使うため、モデルに定義した`delete()`メソッドが呼ばれません。論理削除に差し替えている、関連ファイルをストレージから消している、削除前に外部システムへ通知している、のいずれも一括削除では飛ばされます。

回避策は3つです。`ModelAdmin.delete_queryset()`を上書きして1件ずつ`Model.delete()`を呼ぶ、既定アクションを外して独自アクションを書く、`admin.site.disable_action`で全体から外し必要なモデルの`actions`にだけ戻す、になります。業務データでは3つ目を既定にすると、モデルが増えたときの取りこぼしが出ません。3つ目と1つ目を組み合わせた実装は次のとおりです。

```
# shop/admin.py 一括削除でもモデルの delete() を通す
from django.contrib import admin

admin.site.disable_action("delete_selected")


@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    actions = ["delete_selected"]

    def delete_queryset(self, request, queryset):
        for obj in queryset:
            obj.delete()
```

### 管理画面のURLを変えcollectstaticで静的ファイルを配る

管理画面のURLは既定で`admin/`です。総当たりの対象になりやすいため、本番では別のパスに割り当て直すのが実務上の下限になります。ただしパスの変更は当て推量を減らすだけで、認証の強度は上がりません。あわせて`is_staff`の立っているアカウントを棚卸しします。

もう1つの落とし穴が静的ファイルです。開発サーバは管理画面のCSSとJavaScriptを自動で配信しますが、本番では[静的ファイルのデプロイ手順](https://docs.djangoproject.com/en/5.2/howto/static-files/deployment/)にあるとおり`collectstatic`で集めたファイルをWebサーバやCDNから配らないと素のHTMLだけが出ます。管理画面が「壊れて見える」報告の多くはこれが原因です。公開前に次の2コマンドを流し、警告が出ないところまで詰めます。

```
python manage.py collectstatic --noinput
python manage.py check --deploy
```

## 5.2 LTSと6.0・6.1の管理画面の差分を移行前に確認する

Django本体の版が変われば、管理画面の既定挙動も変わります。[公式のダウンロードページ](https://www.djangoproject.com/download/)によれば、2026年9月時点の最新は6.1系（6.1.1）、長期サポート版は5.2系（5.2.17）で、5.2の延長サポートは2028年4月まで、次のLTSは2027年4月予定の6.2系です。6.0系は2026年8月に主要サポートを終えており、本番運用ではLTSを選ぶのが基本線になります。カスタマイズを持ち込んでいるなら、次の差分が移行時の確認対象です。

### 6.1で変わったlist\_select\_relatedの既定挙動とaction()の指定

[6.1のリリースノート](https://docs.djangoproject.com/en/6.1/releases/6.1/)で管理画面に関わる変更のうち、既存のModelAdminに影響が出るのは次の3点です。

- `list_select_related`が`False`（既定）のとき、変更一覧が引くのは`list_display`に指定した外部キーだけになった。外部キーの多いモデルでは一覧のクエリが軽くなる
- `action()`デコレータに`location`引数が加わり、アクションを変更一覧だけでなく変更画面にも置けるようになった。`description_plural`で一覧側の表示名も分けられる
- 変更画面の入力欄がラベルの下へ移り、ヘルプテキストと検証エラーの位置も変わった。テンプレートやCSSを上書きしているなら描画の確認が要る

1点目は改善ですが、従来「全外部キーが引かれる前提」で`list_display`に載せていない関連先をメソッド経由で表示していた場合、クエリが増える側に振れます。移行時は一覧の発行クエリ本数を実測して比べます。削除確認画面の表示件数を制限する`delete_confirmation_max_display`も6.1で加わり、既定は`None`（切り詰めなし）です。

### 6.0のアイコン差し替えとmessage\_userの表示水準を合わせる

[6.0のリリースノート](https://docs.djangoproject.com/en/6.1/releases/6.0/)では、管理画面のアイコンがFont Awesome Free 6.7.2に差し替えられ、`AdminSite.password_change_form`でパスワード変更画面のフォームを差し替えられるようになりました。移行で見た目が変わるのは`messages.DEBUG`と`messages.INFO`の扱いです。従来は`SUCCESS`と同じ見た目でしたが、6.0で別のアイコンとCSSに分かれました。`ModelAdmin.message_user()`は既定で`INFO`の水準を使うため、従来と同じ成功表示を保つなら呼び出し側で`SUCCESS`を渡します。

### 5.2で入ったextrabodyとadmindocsの権限制限を確認する

LTSの[5.2リリースノート](https://docs.djangoproject.com/en/5.2/releases/5.2/)で管理画面に入った変更は3点です。`admin/base.html`に`extrabody`ブロックが加わって独自コードを差し込めるようになり、`URLField`の値がリンクとして描画されるようになり、`admindocs`のモデルページが`view`または`change`権限の利用者に限定されました。3点目は、社内のドキュメント参照を管理画面に頼っていた運用で「見えていたページが見えなくなる」形で表面化します。移行前に、誰にどの権限が付いているかを先の権限一覧のスクリプトで書き出して突き合わせます。

## adminのまま本番運用してよい条件と別画面へ作り直す判断条件

Djangoのadminは「作り込む対象」ではなく「線を引いて使う対象」です。線を越えて粘ると、標準のテンプレートとフォームの上に業務ロジックが積み上がり、自作より保守しにくくなります。

### 公式が示す想定利用者はサイト管理者でありサイト訪問者ではない

判断の根拠は[公式チュートリアル](https://docs.djangoproject.com/en/5.2/intro/tutorial02/)の一文にあります。管理画面はサイトの訪問者が使うことを想定しておらず、サイト管理者のためのものである、と明記されています。これは機能の不足ではなく、誰の操作を想定して画面が組まれているかという設計方針の宣言です。社外の利用者へ開放する構成は、権限を細かく設定できたとしても仕様の想定外になります。会員が自分のデータを編集する画面や取引先が申請を出す画面は、アプリ側のビューとして作ります。

### adminのまま運用してよい3条件とそのとき触る設定の範囲を決める

次の3条件を全て満たすなら、adminのまま本番に載せて構いません。自作すると認証・権限・履歴・絞り込みを作り直すだけの工数になります。

- 利用者が社内の担当者に限られ、全員に`is_staff`を与えて差し支えない
- 操作が単票の追加・修正・参照に収まり、承認や差し戻しの段階を持たない
- データの見せ分けがモデル単位か、`get_queryset`での単純な絞り込みで表現できる

この範囲で触るのは、`list_display`・`search_fields`・`list_filter`・`readonly_fields`・`autocomplete_fields`・グループ設計と一括削除の扱いまでです。テンプレートの全面上書きや独自ビューの大量追加が視野に入った時点で、条件のどれかが崩れています。

### 別画面へ作り直しに切り替える4条件とその先の作り方の選択肢を比べる

次のいずれか1つでも該当したら、adminを業務画面として使うのをやめます。該当したら例外なく切り替える判断で構いません。

- 承認・差し戻し・並行編集など、状態遷移を伴う業務フローを画面で表現する必要がある
- 社外の利用者、または権限を細かく分けた多数の利用者が日常的に触る
- 1画面に複数モデルをまたぐ入力や、集計を見ながらの編集が要る
- 操作ログを監査の証跡として使い、管理画面以外の更新経路も存在する

切り替え先は2通りです。DjangoのままビューとFormで組むなら、認証とパーミッションを流用できるため移行の断絶が小さく済みます。画面をJavaScript側へ寄せるなら、DjangoをAPIとして残して[Django REST Framework（DRF）とは？Djangoで最短にREST APIを作る仕組みと使いどころ](https://www.issoh.co.jp/tech/details/3277/)のシリアライザと権限クラスへ責務を移し、管理画面は[React-adminとは？管理画面を最速で作るReactフレームワークの使い方](https://www.issoh.co.jp/tech/details/3609/)のような専用フレームワークで組みます。前者は保守要員がPython側で足りる場合に向き、後者の対象は画面の要求が複雑で担当を分けられる案件です。同じ自動生成型をNode.js側で比べるなら[AdminJSとは？Node.jsの管理画面を自動生成する使い方【v7・ESM対応】](https://www.issoh.co.jp/tech/details/2853/)が参考になります。案件としての採用判断は[Djangoで作られたWebアプリの例｜向く4類型と実採用事例・見積もりの見方](https://www.issoh.co.jp/column/details/16918/)にまとめました。

## よくある質問

Django管理画面の設定と運用でよく問われる点です。

### 管理画面のURLを既定のパスから変更できますか？

変更できます。URLconfで`admin.site.urls`を割り当てるパスを書き換えるだけで、既定の`admin/`以外に置けます。総当たりのアクセスは減りますが、認証そのものは強くなりません。`is_staff`の棚卸しのほうが実効があり、社内ネットワークやVPN経由に限定できる構成なら、URLの変更より先にそちらを検討します。

### 一般会員のユーザーを管理画面にログインさせても問題ありませんか？

避けます。公式チュートリアルは管理画面をサイト管理者のためのものと明記しており、権限を絞っても想定外という位置づけは変わりません。会員が自分のデータを編集する画面は、アプリ側のビューとFormで作ります。ログイン自体は`is_staff`のフラグ1つで通るため、会員登録の処理でこのフラグに触れていないかを確認します。

### 管理画面の一覧が重いとき、どこから手を入れますか？

関連先の取得から見ます。`list_display`にメソッド経由で外部キーの先の値を出していると、自動の`select_related()`が効かず行ごとにクエリが増えます。`list_select_related`に対象を明示するのが最初の一手です。次に`list_per_page`（既定100）を下げ、ファセット件数が不要なら`show_facets`を`NEVER`にします。追加画面が重いのは別の原因で、選択欄を`autocomplete_fields`へ移す対処になります。

### 一括削除でモデルのdelete()が呼ばれないのはなぜですか？

既定の削除アクションが効率のため`QuerySet.delete()`を使う仕様だからで、公式も警告として明記しています。論理削除や関連ファイルの削除をモデルの`delete()`に書いていると、一括削除では実行されません。`ModelAdmin.delete_queryset()`の上書き、独自アクション、`admin.site.disable_action`による全体除外のいずれかで対処します。

### Djangoのどの版で管理画面を作るのが無難ですか？

本番は長期サポート版に寄せます。2026年9月時点なら5.2系がLTSで延長サポートは2028年4月まで、最新の機能リリースは6.1系です。新規案件で3年単位の保守を見込むなら5.2系で組み、2027年4月予定の6.2 LTSが出た時点で移行を検討する流れが読みやすい形になります。6.1系を選ぶ場合は、一覧の関連先取得の既定挙動が変わった点と、変更画面の入力欄の配置が変わった点を先に確認しておきます。

### 管理画面だけで業務システムを完結させることはできますか？

操作が単票の追加・修正・参照に収まり、利用者が社内の担当者だけで、承認の段階を持たないなら完結します。承認の状態遷移が入る、社外の利用者が触る、複数モデルを跨ぐ入力が要る、監査の証跡が要る、のいずれかに当たった時点で別画面へ切り替えます。

## 関連記事

- [Djangoとは？Python製Webフレームワークの特徴・MVT・始め方を入門解説](https://www.issoh.co.jp/tech/details/3275/)：全体の位置づけとMVT、LTSの選び方です。
- [Djangoのログイン機能：標準authの範囲とカスタムユーザー・allauth](https://www.issoh.co.jp/tech/details/17099/)：アプリ本体側の認証と、管理画面の入室条件の切り分けです。
- [Django ORMのクエリ設計](https://www.issoh.co.jp/tech/details/17082/)：get\_querysetで重ねた条件がいつ評価されるかの土台です。
- [django-filterで一覧検索を実装する｜FilterSet設計とDRF指定の判断](https://www.issoh.co.jp/tech/details/17107/)：利用者向けの一覧へ絞り込みを出す場合の受け皿です。
- [Djangoで作られたWebアプリの例｜向く4類型と実採用事例・見積もりの見方](https://www.issoh.co.jp/column/details/16918/)：案件としての採用判断と見積もりです。
- [Django REST Framework（DRF）とは？Djangoで最短にREST APIを作る仕組みと使いどころ](https://www.issoh.co.jp/tech/details/3277/)：API化した場合の受け皿です。
- [React-adminとは？管理画面を最速で作るReactフレームワークの使い方](https://www.issoh.co.jp/tech/details/3609/)：JavaScript側で組む選択肢です。
- [AdminJSとは？Node.jsの管理画面を自動生成する使い方【v7・ESM対応】](https://www.issoh.co.jp/tech/details/2853/)：同じ自動生成型の比較対象です。

---

出典: [Django管理画面の設計：admin標準の範囲とModelAdmin・権限の実装](<https://www.issoh.co.jp/tech/details/17078/>)（株式会社一創）
