概要(「Web アプリ実践」は“全部をつなげて動かす”フェーズ)
ここまでで、Django のモデル・ビュー・URL・テンプレート・認証・セッション・設定・分割構造など、部品ごとの話をかなり見てきましたよね。
「Web アプリ実践」は、その部品をバラバラに眺めるのではなく、
ひとつの具体的なアプリのゴールを決める
そこに向かってモデルを設計し
URL とビューで画面の流れを作り
テンプレートで見た目を整え
必要なら認証やフォーム、バリデーションも組み込む
という「全部をつなげて動かす」フェーズです。
ここでは、超シンプルな実践例として
「ログインしたユーザーだけが使える、個人用 ToDo リストアプリ」
を題材にします。
Django を使って、最初の一歩から「ちゃんと動く Web アプリ」になるところまでを、流れでかみ砕いていきます。
アプリのゴールを決める(仕様を日本語で言語化する)
まずはコードではなく「やりたいこと」をはっきりさせる
いきなりコードに行く前に、仕様を日本語で決めます。
今回の ToDo アプリのゴールを、あえてシンプルに書くとこうなります。
ユーザーはログインできる。
ログインしたユーザーは、自分専用の ToDo を登録できる。
ToDo は「タイトル」と「完了フラグ」を持つ。
一覧画面で、自分の ToDo を一覧表示できる。
新規追加フォームから ToDo を追加できる。
チェックボックスで完了状態を切り替えられる。
このくらいの粒度で十分です。
大事なのは、「どんな画面があって、どんなデータを扱うか」が頭に浮かぶこと。
ここがぼんやりしたままコードを書き始めると、途中で迷子になります。
モデル設計(データの形を先に固める)
ToDo モデルを Django で定義する
仕様が決まったら、まず「データの形」を決めます。
Django では models.py に書きます。
今回必要なのは、「ToDo」という概念です。
ユーザーごとに ToDo を持つので、User との紐づけも必要になります。
# todo/models.py
from django.db import models
from django.contrib.auth.models import User
class Todo(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField("タイトル", max_length=200)
is_done = models.BooleanField("完了", default=False)
created_at = models.DateTimeField("作成日時", auto_now_add=True)
def __str__(self):
return self.title
Pythonここで重要なのは二つです。
一つ目は、User への外部キーを持っていること。
これによって「どの ToDo がどのユーザーのものか」がはっきりします。
二つ目は、is_done を BooleanField にしていること。
完了かどうかを True/False で持つことで、ビュー側での処理がシンプルになります。
モデルを書いたら、いつもの流れでマイグレーションを作って適用します。
python manage.py makemigrations
python manage.py migrate
Pythonこれで DB に todo_todo テーブルができ、ToDo を保存できる土台が整いました。
URL・ビュー・テンプレートで「画面の流れ」を作る
一覧画面の URL とビューを作る
次に、「ログインしたユーザーの ToDo 一覧」を表示する画面を作ります。
まずはアプリ側の urls.py から。
# todo/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.todo_list, name="todo_list"),
]
Pythonプロジェクト側の urls.py で、この todo.urls をどこかにぶら下げます。
# config/urls.py
from django.urls import path, include
urlpatterns = [
path("todo/", include("todo.urls")),
]
Pythonこれで /todo/ にアクセスすると、todo_list ビューが呼ばれるようになります。
ビューはこう書きます。
# todo/views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from .models import Todo
@login_required
def todo_list(request):
todos = Todo.objects.filter(user=request.user).order_by("-created_at")
return render(request, "todo/todo_list.html", {"todos": todos})
Pythonここでのポイントは二つです。
login_required デコレータで「ログイン必須」にしていること。
クエリで user=request.user を指定し、「自分の ToDo だけ」を取っていること。
これで、「ログインしたユーザーごとに、自分の ToDo だけが見える」状態になります。
一覧画面のテンプレートを書く
テンプレートを作ります。
フォルダ構成はこうしておきます。
todo/
templates/
todo/
todo_list.html
中身はシンプルで構いません。
<!-- todo/templates/todo/todo_list.html -->
{% extends "base.html" %}
{% block content %}
<h1>あなたの ToDo リスト</h1>
<form method="post" action="{% url 'todo_add' %}">
{% csrf_token %}
<input type="text" name="title" placeholder="新しい ToDo を入力">
<button type="submit">追加</button>
</form>
<ul>
{% for todo in todos %}
<li>
<form method="post" action="{% url 'todo_toggle' todo.id %}" style="display:inline;">
{% csrf_token %}
<input type="checkbox" onchange="this.form.submit()" {% if todo.is_done %}checked{% endif %}>
</form>
{% if todo.is_done %}
<s>{{ todo.title }}</s>
{% else %}
{{ todo.title }}
{% endif %}
</li>
{% empty %}
<li>まだ ToDo はありません。</li>
{% endfor %}
</ul>
{% endblock %}
Pythonここでは、一覧表示だけでなく
新規追加フォーム
完了状態を切り替えるチェックボックス
も一緒に置いています。
このあと、これらを受け取るビューを作ります。
フォームと POST 処理(データを「作る」「更新する」)
ToDo を追加するビュー
新規追加フォームは、action="{% url 'todo_add' %}" に飛ぶようにしました。
この URL とビューを定義します。
# todo/urls.py
urlpatterns = [
path("", views.todo_list, name="todo_list"),
path("add/", views.todo_add, name="todo_add"),
path("toggle/<int:pk>/", views.todo_toggle, name="todo_toggle"),
]
Python追加用ビューはこうです。
# todo/views.py
from django.shortcuts import redirect
@login_required
def todo_add(request):
if request.method == "POST":
title = request.POST.get("title", "").strip()
if title:
Todo.objects.create(user=request.user, title=title)
return redirect("todo_list")
Pythonここでやっていることは、とてもシンプルです。
POST で送られてきた title を取り出す。
空でなければ、自分のユーザーに紐づく Todo を作成する。
最後に一覧ページにリダイレクトする。
フォームクラス(forms.py)を使う方法もありますが、
最初の実践としては「request.POST から取り出してバリデーションする」だけでも十分です。
完了フラグを切り替えるビュー
チェックボックスのフォームは、todo_toggle に飛ぶようにしました。
ビューはこう書けます。
@login_required
def todo_toggle(request, pk):
if request.method == "POST":
todo = Todo.objects.filter(id=pk, user=request.user).first()
if todo is not None:
todo.is_done = not todo.is_done
todo.save()
return redirect("todo_list")
Pythonここでのポイントは二つです。
id だけでなく user=request.user も条件に入れていること。
これにより、「他人の ToDo を勝手に操作する」ことを防げます。
is_done を反転させて save していること。
チェックボックスの ON/OFF に応じて値を送る方法もありますが、
「押されたら反転」という仕様にするとコードが簡単になります。
これで、「一覧画面から ToDo を追加し、完了状態を切り替える」という一連の操作が、
ログインユーザーごとに完結するようになりました。
認証との接続(ログインしていない人をどう扱うか)
login_required が守ってくれているもの
今回の todo_list, todo_add, todo_toggle には、すべて login_required を付けました。
これにより、ログインしていないユーザーが /todo/ にアクセスすると、
自動的にログインページにリダイレクトされます。
ログインページの URL は、settings.py の LOGIN_URL で決まります。
デフォルトは /accounts/login/ なので、
そこに対応するログインビューとテンプレートを用意しておけば OK です。
すでに Django 認証の話で見たように、
ログイン処理自体は Django に任せてしまい、
「ログインしている前提の画面」だけを自分で作る、という分担が現実的です。
request.user を前提にした設計にする
ToDo アプリの中では、
「ユーザー ID をフォームから送らせる」ようなことは一切していません。
すべて request.user を前提にしています。
Todo.objects.filter(user=request.user)
Todo.objects.create(user=request.user, …)
Todo.objects.filter(id=pk, user=request.user)
このように、「ログインしているユーザー」を軸にデータを扱うことで、
他人のデータを触られない
URL をいじられても、自分のもの以外は操作できない
という状態を作れます。
実践的な Web アプリでは、この「request.user を軸にする」感覚がとても重要です。
ここまでで「ひとつの Web アプリ」が完成している
何ができるようになったかを整理する
今作った ToDo アプリは、機能としてはシンプルですが、
Web アプリとしての要素は一通り揃っています。
ログイン機能(Django 認証)
ユーザーごとのデータ管理(Todo モデルと外部キー)
一覧表示(GET)
新規作成(POST)
更新(完了フラグの切り替え)
URL 設計とビューの分担
テンプレートによる表示
つまり、「実務でよくある CRUD+ログイン」の最小セットを、
一通り体験できている状態です。
ここから先は、欲しい機能に応じて
削除機能を追加する
締切日や優先度を追加する
ページネーションを付ける
API 化してフロントエンドから叩けるようにする
といった方向に広げていけばよく、
やることは「同じパターンの応用」です。
実践で一番大事なのは「小さく作って、動かして、広げる」こと
いきなり「完璧な設計」を目指す必要はありません。
むしろ、最初は
モデルを一つ決める
それを一覧表示する
新規追加だけでもいいから動かす
というところまでを、できるだけ早く終わらせる方がいいです。
動くものが一つできると、
URL とビューとテンプレートのつながり
モデルと ORM の使い方
ログインとの関係
が一気に立体的に見えてきます。
そこから、「じゃあ次は編集画面を作ろう」「削除も付けよう」と、
一歩ずつ階段を上がっていけばいい。
まとめ(Web アプリ実践は「知識を一本の線にする作業」)
Python の Web フレームワーク(ここでは Django)での Web アプリ実践は、
仕様を日本語で決める
モデルでデータの形を決める
URL とビューで画面の流れを作る
テンプレートで見た目を作る
フォームと POST でデータを作成・更新する
認証と組み合わせて「誰のデータか」を守る
というステップを、ひとつのアプリの中でつなげていく作業です。
