学ぶ|Web開発入門 #5

SQLとDjangoモデルの基本を独学で身につける完全ガイド|CRUD・JOIN・マイグレーションまで

  • SQL
  • データベース
  • Django
  • Web開発入門
  • プログラミング未経験

📋 この記事の目次
  1. データベースは「整理された巨大な書庫」だと考える
  2. Part A: SQLの基礎
  3. Part B: 高度なクエリ
  4. Part C: Djangoモデル(Pythonの中でテーブルを表現する)
  5. Part D: マイグレーション
  6. Part E: Django Shellと管理画面
  7. 実践プロジェクト:ゲストブックにデータベースを接続する
  8. 🧠 理解度チェック(一部抜粋)
  9. 挫折ポイントTOP3と対処法
  10. この先、何を学べばいいか
  11. まとめ
  12. 🎓 理解度テスト

前回、ゲストブックの画面は作りましたが、表示していたのはビューの中に直接書いたダミーデータでした。今回は、実際に訪問者からのメッセージをデータベースに保存し、検索・並び替えできるようにしていきます。

「データベースって結局、Excelと何が違うの?」 「SQLのSELECT文は読めるけど、Djangoでどう使うのか繋がらない」

この2つを、ゲストブックのメッセージ保存機能を作りながら解消していきます。


データベースは「整理された巨大な書庫」だと考える

  • テーブル = 「1つのテーマごとの棚」(例: メッセージ棚、訪問者棚)
  • カラム(列) = 「棚の中の項目」(名前・本文・投稿日時…)
  • 行(レコード) = 「棚に収められた1件分のデータ」
  • JOIN(結合) = 「複数の棚の情報を、共通の合言葉(ID)で紐付けて一緒に調べる」作業

Excelとの決定的な違いは、大量のデータの中から条件に合うものを高速に探し出せること、そして複数の表を関連付けて矛盾なく管理できることです。

🧓 ベテランの現場コラム 「最初はExcelで管理していたデータが増えすぎて破綻した」という相談は、独学者からも現場の若手からも非常によく聞きます。1000件を超えたあたりから、Excelでの手作業管理は限界が見えてきます。データベースの学習コストは決して低くありませんが、「データが増えても崩れない土台」を早めに知っておく価値は大きいです。


Part A: SQLの基礎

テーブルとデータ型・SQLiteの使用

CREATE TABLE messages (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    visitor_name TEXT NOT NULL,
    body TEXT NOT NULL,
    score INTEGER,
    posted_at TEXT
);

INTEGER(整数)、TEXT(文字列)のように、カラムごとに「どんな種類のデータを入れるか」を決めておくことで、データの矛盾(数字を入れるべき欄に文字列が入る、など)を防ぎます。今回はDjangoの標準データベースであるSQLite(追加のインストール作業なしで使える軽量データベース)を使います。

基本コマンド(CRUD)

データベース操作の基本は「Create(作成)・Read(読み取り)・Update(更新)・Delete(削除)」の頭文字を取ったCRUDです。

-- Create
INSERT INTO messages (visitor_name, body, score) VALUES ('山田花子', '参考になりました', 5);

-- Read
SELECT * FROM messages;

-- Update
UPDATE messages SET score = 4 WHERE id = 1;

-- Delete
DELETE FROM messages WHERE id = 1;

Part B: 高度なクエリ

フィルタリング・並び替え・集計・結合

-- フィルタリング
SELECT * FROM messages WHERE score >= 4;

-- 並び替えと件数制限
SELECT * FROM messages ORDER BY posted_at DESC LIMIT 10;

-- 集計関数
SELECT AVG(score), COUNT(*) FROM messages;

-- テーブル結合(visitorsテーブルと組み合わせる想定)
SELECT messages.body, visitors.email
FROM messages
JOIN visitors ON messages.visitor_id = visitors.id;

JOINは、「メッセージ棚」と「訪問者棚」をvisitor_idという共通の合言葉で紐付け、両方の情報を一度に取り出す操作です。

インデックス

CREATE INDEX idx_messages_posted_at ON messages(posted_at);

インデックスは「本の索引」に相当します。データ量が増えたときに、特定のカラムでの検索を高速化するための仕組みです。ただし、インデックスを増やしすぎるとデータの追加・更新が遅くなるトレードオフもあるため、「よく検索条件に使うカラムに絞って」設定するのが基本です。


Part C: Djangoモデル(Pythonの中でテーブルを表現する)

モデルの定義

# guestbook/models.py
from django.db import models

class Visitor(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField(blank=True)

class Message(models.Model):
    visitor = models.ForeignKey(Visitor, on_delete=models.CASCADE, related_name="messages")
    body = models.TextField()
    score = models.IntegerField(default=3)
    posted_at = models.DateTimeField(auto_now_add=True)

Djangoのモデルは、SQLのCREATE TABLEをPythonのクラスとして表現したものです。SQL文を直接書かなくても、Pythonの文法だけでテーブル構造を定義できます。

リレーションシップとon_delete

ForeignKeyは「1件のメッセージは、1人の訪問者に紐づく」という関係(多対1)を表します。on_delete=models.CASCADEは「訪問者データが削除されたら、その人のメッセージも一緒に削除する」という挙動の指定です。他に「削除を許可しない」PROTECTなどの選択肢もあります。

主なフィールドタイプ

フィールド 用途
CharField(max_length=...) 短い文字列(名前など)
TextField() 長い文字列(本文など)
IntegerField() 整数
DateTimeField(auto_now_add=True) 作成時に自動で日時を記録
EmailField() メールアドレス(簡易な形式チェック付き)
ForeignKey(...) 他のモデルとの関連付け

Part D: マイグレーション

なぜマイグレーションが必要か・基本ワークフロー

モデル(Pythonのクラス)を書いただけでは、まだ実際のデータベースにテーブルは作られていません。マイグレーションは、「モデルの定義」と「実際のデータベースの構造」を同期させる仕組みです。

python manage.py makemigrations   # モデルの変更内容を「設計図」として書き出す
python manage.py migrate          # 設計図をもとに実際のデータベースへ反映する

🧓 ベテランの現場コラム モデルを直接いじって「動かない」と焦る新人によくあるのが、makemigrationsだけ実行してmigrateを忘れているケースです。「設計図を描いた」だけでは工事は始まりません。この2段階セットを必ず覚えておきましょう。


Part E: Django Shellと管理画面

Django Shellでのデータ操作

python manage.py shell
from guestbook.models import Visitor, Message

# Create(INSERT相当)
visitor = Visitor.objects.create(name="山田花子", email="hanako@example.com")
Message.objects.create(visitor=visitor, body="参考になりました", score=5)

# Read(SELECT相当)
Message.objects.filter(score__gte=4).order_by("-posted_at")

# リレーション操作
visitor.messages.all()   # related_name="messages" で辿れる

SQLのSELECT ... WHERE ... ORDER BYが、Djangoではfilter()order_by()というPythonのメソッドとして表現されています。これをORM(Object-Relational Mapping) と呼びます。

Django Admin(管理画面)

# guestbook/admin.py
from django.contrib import admin
from .models import Visitor, Message

admin.site.register(Visitor)
admin.site.register(Message)
python manage.py createsuperuser
python manage.py runserver
# ブラウザで /admin/ にアクセス

たった数行の登録だけで、データの一覧・追加・編集・削除ができるGUI画面が自動生成されます。ゲストブックに届いたメッセージを、コードを書かずにブラウザ上で確認・削除できるようになります。


実践プロジェクト:ゲストブックにデータベースを接続する

  1. VisitorMessageモデルを定義する
  2. マイグレーションを実行し、実際のテーブルを作成する
  3. Django Shellでテストデータを何件か作成する
  4. ビュー(views.py)を、ダミーデータではなくMessage.objects.all()から取得する形に書き換える
  5. 管理画面にモデルを登録し、ブラウザから内容を確認する

これで、フォームから送られてきたメッセージが実際に保存され、ページを再読み込みしても消えない状態になります。


🧠 理解度チェック(一部抜粋)

  • Q. マイグレーションが必要な理由は? → モデル(Pythonの定義)と実際のデータベースの構造を一致させるため
  • Q. on_delete=models.CASCADEの意味は? → 親データが削除されたときに、関連する子データも一緒に削除する設定
  • Q. JOINは何をしているか? → 複数のテーブルを共通のIDで紐付けて、まとめて情報を取得する操作

挫折ポイントTOP3と対処法

1. 「マイグレーションのエラーが出て進めない」問題

既存のデータと矛盾する変更(必須項目を後から追加する等)をしようとすると発生しやすいです。デフォルト値を指定するか、開発初期であればデータベースファイルごと作り直すのも選択肢です。

2. 「SQLとDjangoのORMの対応関係が分からない」問題

filter() = WHEREorder_by() = ORDER BY.aggregate() = 集計関数、と1対1で対応づけて覚えると理解が早まります。

3. 「N+1問題」(データが増えると急に遅くなる)

リレーションを辿るたびに個別にクエリが発行され、件数が増えると極端に遅くなる現象です。select_related()prefetch_related()という関連データを一括取得する仕組みがありますが、これは中級者向けの話題としてまず存在だけ知っておきましょう。

🧓 ベテランの現場コラム データベース関連の不具合は、開発中はデータ件数が少なくて気づかず、本番でデータが増えてから初めて表面化することが多いです。「今は速いから大丈夫」ではなく、「件数が増えても大丈夫な書き方か」を意識する視点は、早いうちから持っておいて損はありません。


この先、何を学べばいいか

データが保存できるようになったら、次は 「JavaScript」でページに動きをつける回に進みます。ここまでは「ページを再読み込みしないと表示が変わらない」状態でしたが、JavaScriptを使うとページを移動せずにその場で表示を更新できるようになります。


まとめ

  • データベースは「整理された巨大な書庫」。テーブル・カラム・行という単位で情報を管理する
  • CRUD(作成・読み取り・更新・削除)が操作の基本
  • DjangoのモデルはPythonでテーブル構造を表現したもの。マイグレーションで実データベースと同期する
  • ORM(filter()order_by())はSQLをPythonの文法で書けるようにした仕組み
  • 管理画面を使えば、コードを書かずにデータの確認・編集ができる

参考にした学習リソースについて

本記事は、ハーバード大学が提供する人気講座「CS50’s Web Programming with Python and JavaScript」の内容を参考にしつつ、独自の題材・独自の構成・自作のサンプルで書き下ろしたオリジナル解説記事です。CS50そのものに興味を持った方は、以下の公式サイトも覗いてみてください。

🎓 理解度テスト

学んだ内容を確認しましょう。全6問。