SQLとDjangoモデルの基本を独学で身につける完全ガイド|CRUD・JOIN・マイグレーションまで
📋 この記事の目次
前回、ゲストブックの画面は作りましたが、表示していたのはビューの中に直接書いたダミーデータでした。今回は、実際に訪問者からのメッセージをデータベースに保存し、検索・並び替えできるようにしていきます。
「データベースって結局、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画面が自動生成されます。ゲストブックに届いたメッセージを、コードを書かずにブラウザ上で確認・削除できるようになります。
実践プロジェクト:ゲストブックにデータベースを接続する
Visitor・Messageモデルを定義する- マイグレーションを実行し、実際のテーブルを作成する
- Django Shellでテストデータを何件か作成する
- ビュー(
views.py)を、ダミーデータではなくMessage.objects.all()から取得する形に書き換える - 管理画面にモデルを登録し、ブラウザから内容を確認する
これで、フォームから送られてきたメッセージが実際に保存され、ページを再読み込みしても消えない状態になります。
🧠 理解度チェック(一部抜粋)
- Q. マイグレーションが必要な理由は? → モデル(Pythonの定義)と実際のデータベースの構造を一致させるため
- Q.
on_delete=models.CASCADEの意味は? → 親データが削除されたときに、関連する子データも一緒に削除する設定 - Q. JOINは何をしているか? → 複数のテーブルを共通のIDで紐付けて、まとめて情報を取得する操作
挫折ポイントTOP3と対処法
1. 「マイグレーションのエラーが出て進めない」問題
既存のデータと矛盾する変更(必須項目を後から追加する等)をしようとすると発生しやすいです。デフォルト値を指定するか、開発初期であればデータベースファイルごと作り直すのも選択肢です。
2. 「SQLとDjangoのORMの対応関係が分からない」問題
filter() = WHERE、order_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そのものに興味を持った方は、以下の公式サイトも覗いてみてください。
- CS50 公式サイト: https://cs50.harvard.edu/x/
🎓 理解度テスト
学んだ内容を確認しましょう。全6問。