Django基礎 #7 Django Admin とビルトイン認証
#1 Django とは でした約束 — Admin が無料で付いてくる — を回収する番です。今回は Django が自動で作ってくれる管理者ページと、同じところで付いてくるビルトイン認証 (User、ログイン、権限) を一息で見ます。シリーズの最終回です。
Admin — モデル登録ワンライナー #
blog/admin.py に 1 行。
from django.contrib import admin
from .models import Post
admin.site.register(Post)これで終わりです。runserver を立ち上げて http://127.0.0.1:8000/admin/ に行くと — まだログインページですね。superuser が必要です。
Superuser を作る #
uv run python manage.py createsuperuser対話形式で username / email / password を入力すれば終わり。これで /admin/ にそのアカウントでログインできます。
ログインすると — Auth (User、Group)、Blog (Post) が左側のメニューに。Post をクリックすると自動で作られた CRUD 画面 が見えます。一覧、生成、修正、削除、検索まで。
コードを 1 行も追加していないのに。これが Django のもっとも強力な約束です。
ModelAdmin — Admin 画面のカスタマイズ #
デフォルト画面は単調です (Post object (1)、Post object (2) …)。ModelAdmin で豊かにします。
from django.contrib import admin
from .models import Post, Tag, Comment
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
# 一覧画面
list_display = ("title", "author", "is_published", "created_at")
list_filter = ("is_published", "created_at", "author")
search_fields = ("title", "content")
date_hierarchy = "created_at"
ordering = ("-created_at",)
list_editable = ("is_published",)
list_per_page = 25
# 詳細画面
fields = ("title", "author", "content", "tags", "is_published")
readonly_fields = ("created_at", "updated_at")
filter_horizontal = ("tags",) # ManyToMany ウィジェットの改善
autocomplete_fields = ("author",) # FK が多いときの検索オートコンプリート
prepopulated_fields = {"slug": ("title",)} # title → slug 自動生成
@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
list_display = ("name", "slug")
search_fields = ("name",)
prepopulated_fields = {"slug": ("name",)}
admin.site.register(Comment)よく使うオプション一覧:
| オプション | 効果 |
|---|---|
list_display | 一覧に表示するカラム |
list_filter | 右サイドバーのフィルタ |
search_fields | 上部の検索ボックス (対象フィールド) |
date_hierarchy | 日付でドリルダウンする上部ナビ |
ordering | デフォルトのソート |
list_editable | 一覧から直接修正可能 |
list_per_page | ページあたり件数 |
fields / fieldsets | 詳細画面のフィールド配置 |
readonly_fields | 読み取り専用フィールド |
filter_horizontal / filter_vertical | M2M の二段ウィジェット |
autocomplete_fields | FK / M2M のオートコンプリート (対象モデルに search_fields が必要) |
prepopulated_fields | 別フィールドから自動入力 (slug が一般的) |
@admin.register(Post) デコレータは admin.site.register(Post, PostAdmin) と同じです。よりすっきりします。
Inline — 親画面で子も一緒に編集 #
Post の詳細画面でその記事の Comment を一緒に表示したい場合。
from django.contrib import admin
from .models import Post, Comment
class CommentInline(admin.TabularInline): # or StackedInline
model = Comment
extra = 1 # 空の行を 1 つ追加
fields = ("author", "body", "created_at")
readonly_fields = ("created_at",)
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ("title", "author")
inlines = [CommentInline]TabularInline— テーブル形式 (1 行に 1 コメント)StackedInline— カード形式 (フィールドを縦に並べる)
カート / 注文項目 / 投稿の添付ファイルのように 親 ↔ 子 関係が明確な場合によく合います。
Admin の見た目以上の強さ #
- 検索 + フィルタ + ページング が自動
- 変更履歴 — 誰がいつ何を変えたかを記録 (Recent Actions)
- 権限体系 — モデル単位の add/change/delete/view 権限が自動生成
- 多言語 — ユーザーの LANGUAGE_CODE に合わせて UI が変わる
- i18n + RTL 対応
小さな社内ツールなら Admin だけで運用画面が完結します。Admin そのものを運用ツールとして使う会社 も多いです。
Admin セキュリティ — 運用の基本 #
/admin/のパスをそのまま置かず変更 (path("private/", admin.site.urls))- IP 制限 (Nginx またはミドルウェア)
- 2 段階認証 (
django-otp、django-allauth-2fa) - superuser は本当に必要な人だけ
詳しい運用セキュリティは 上級 #7 デプロイセキュリティ で。
ビルトイン認証 — django.contrib.auth
#
Admin の基盤がまさに django.contrib.auth です。すでに INSTALLED_APPS に入っており、migrate 時に User、Group、Permission テーブルが作られています。
User モデル
#
from django.contrib.auth import get_user_model
User = get_user_model() # コンベンション — settings.AUTH_USER_MODEL に従う
user = User.objects.create_user(
username="curtis",
email="me@example.com",
password="secret123", # 自動でハッシュ化される
)
user.set_password("new-password") # パスワード変更
user.save()
user.check_password("new-password") # → Truecreate_user と set_password がパスワードハッシュ (PBKDF2 がデフォルト) を自動で。絶対に平文で保存してはいけません。
カスタム User — 最初から推奨 #
デフォルト User も動作しますが、新しいプロジェクトは最初からカスタム User モデルで始める のがコンベンションです。後で変えるのが非常に難しいです。
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
bio = models.TextField(blank=True)
avatar = models.ImageField(upload_to="avatars/", blank=True, null=True)AUTH_USER_MODEL = "accounts.User"深いカスタマイズ (メールログイン、権限など) は 中級 #4 ユーザー / 権限 で。
ログイン / ログアウト — ビルトイン view #
直接作る必要はありません。django.contrib.auth.urls に全部あります。
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("accounts/", include("django.contrib.auth.urls")),
path("blog/", include("blog.urls")),
]include("django.contrib.auth.urls") の 1 行に付いてくる URL:
| 名前 | パス | 何をするか |
|---|---|---|
login | /accounts/login/ | ログイン |
logout | /accounts/logout/ | ログアウト |
password_change | /accounts/password_change/ | パスワード変更 |
password_change_done | /accounts/password_change/done/ | 変更完了 |
password_reset | /accounts/password_reset/ | パスワード再設定 (メール) |
password_reset_done / confirm / complete | … | 再設定フロー |
view はすべてあるのに テンプレートは自分で 作らなければなりません。
{% extends "base.html" %}
{% block content %}
<h1>ログイン</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">ログイン</button>
</form>
{% if form.errors %}
<p>ID またはパスワードが間違っています。</p>
{% endif %}
<p><a href="{% url 'password_reset' %}">パスワードを忘れた方はこちら</a></p>
{% endblock %}このファイル 1 つでログインが動作します。logout / password_* も同じ場所 (templates/registration/) に作ります。
ログイン後のリダイレクト #
LOGIN_URL = "/accounts/login/"
LOGIN_REDIRECT_URL = "/blog/"
LOGOUT_REDIRECT_URL = "/blog/"会員登録は自分で #
ビルトインは ログイン / ログアウト / パスワード だけ提供します。会員登録は自分で作るか django-allauth のようなパッケージを使います。
from django.contrib.auth import login
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import redirect, render
def signup(request):
if request.method == "POST":
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
return redirect("blog:post_list")
else:
form = UserCreationForm()
return render(request, "registration/signup.html", {"form": form})UserCreationForm もビルトイン — username + password + password 確認フィールドを備えた ModelForm です。
@login_required — ログイン保護
#
view 関数の上にデコレータを 1 行。
from django.contrib.auth.decorators import login_required
@login_required
def post_new(request):
...ログインしていないユーザーがアクセスすると自動で LOGIN_URL にリダイレクト (本来行こうとしていた URL は ?next=... クエリで付き、ログイン後に戻ってきます)。
request.user — 現在のユーザー
#
def my_page(request):
if request.user.is_authenticated:
username = request.user.username
...{% if user.is_authenticated %}
<p>{{ user.username }} さんようこそ。</p>
<a href="{% url 'logout' %}">ログアウト</a>
{% else %}
<a href="{% url 'login' %}">ログイン</a>
{% endif %}request.user はログインしていなければ AnonymousUser インスタンスです (is_authenticated が False)。だから if request.user: のような検査は意味がありません — 必ず is_authenticated で。
権限 — @permission_required / user.has_perm
#
Django はモデルごとに自動的に 4 つの権限を作ります — add_<model>、change_<model>、delete_<model>、view_<model>。
from django.contrib.auth.decorators import permission_required
@permission_required("blog.delete_post", raise_exception=True)
def post_delete(request, post_id):
...if request.user.has_perm("blog.change_post"):
...{% if perms.blog.change_post %}
<a href="...">修正</a>
{% endif %}Group で権限のまとまりを作り、ユーザーにグループを割り当てるのが運用パターンです。深い権限モデルは 中級 #4 ユーザー / 権限 で。
まとめ #
今回つかんだもの:
admin.site.register(Model)の 1 行で自動 CRUD UIcreatesuperuserで管理者アカウントModelAdmin—list_display、list_filter、search_fields、date_hierarchy、…- Inline — 親画面で子も一緒に編集
- ビルトイン
User—create_user、set_password、check_password - 新しいプロジェクトは 最初からカスタム User モデル を推奨
include("django.contrib.auth.urls")でログイン / ログアウト / パスワードフロー- テンプレートは
templates/registration/に自分で @login_required、request.user.is_authenticated- 権限 — モデル別に自動生成、
@permission_required、user.has_perm、テンプレートperms.app.codename - Admin は運用ツールとしてそのまま使えるレベル — ただしセキュリティ (パス変更、2FA、IP 制限) は必須
シリーズのまとめ #
7 編を一息で整理すると:
- #1 Django とは — フルスタックモノリスの位置
- #2 プロジェクトのセットアップ — uv + startproject + startapp
- #3 Models と ORM 基礎 — モデル、マイグレーション、QuerySet
- #4 URL と Views — URLconf、FBV、render
- #5 Templates と静的ファイル — テンプレート継承、static
- #6 Forms と ModelForm — フォーム検証、ModelForm、ファイルアップロード
- #7 Admin と認証 — 自動 CRUD、ログイン、権限 ← 今回
この 7 編で小さなブログを 1 軒建てるのに必要な部品がすべて揃いました。1 人で小さなサイドプロジェクトを作れるレベルです。
次のシリーズ Django 中級 #1 CBV の深さ では FBV の繰り返しパターンを縮める クラスベースビュー を扱います。ListView、DetailView、CreateView、UpdateView、DeleteView の 5 つで同じ CRUD をはるかに短く書ける流れを見ます。その上に 中級 #2 ORM 中級 の select_related / prefetch_related、中級 #7 テスト まで — 1 軒を本当に運用できる形にしていく流れです。
ここまで付いてきてくださった方に感謝します。フルスタック 1 軒を建てる楽しさが始まりますように。