本文へスキップ
BecomeCoder

Djangoコース · 第5章 モデルとデータベース · レッスン23

テーブルをつなぐ ― ForeignKey

ブラウザで完結

導入

「著者」と「本」、「ユーザー」と「投稿」。データは互いに関係しています。この「1対多」の関係を表すのが ForeignKey(外部キー です。

説明

「1人の著者が、複数の本を持つ」を考えます。Book に「どの著者のものか」を指す ForeignKey を持たせます。

import django
from django.conf import settings
if not settings.configured:
    settings.configure(DEBUG=True, SECRET_KEY="dev", INSTALLED_APPS=[],
        DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}})
    django.setup()

from django.db import models, connection

class Author(models.Model):
    name = models.CharField(max_length=50)
    class Meta:
        app_label = "library"

class Book(models.Model):
    title = models.CharField(max_length=100)
    # 「多」の側に ForeignKey を置く。著者が消えたら本も消す(CASCADE)。
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    class Meta:
        app_label = "library"

with connection.schema_editor() as schema:
    schema.create_model(Author)
    schema.create_model(Book)

# 著者を作り、その著者の本を登録
aki = Author.objects.create(name="あき")
bob = Author.objects.create(name="ぼぶ")
Book.objects.create(title="Django入門", author=aki)
Book.objects.create(title="Python超入門", author=aki)
Book.objects.create(title="SQL入門", author=bob)

# 本 → 著者(1 の側へたどる)
b = Book.objects.get(title="Django入門")
print("この本の著者:", b.author.name)          # あき

# 著者 → 本(多 の側へたどる。「モデル名_set」で逆参照)
print("あきの本:", [x.title for x in aki.book_set.all()])   # 2冊

# 関連でまたぐ絞り込み:著者名で本を検索(author__name)
print("ぼぶの本:", [x.title for x in Book.objects.filter(author__name="ぼぶ")])
  • ForeignKey(Author, on_delete=models.CASCADE) … 「多」の側(Book)に置き、「1」の側(Author)を指します。on_delete=CASCADE は「著者が削除されたら、その本も一緒に削除」という意味。
  • 順方向book.author で著者オブジェクトへ。
  • 逆方向author.book_set.all() で、その著者の本すべてへ。
  • またぎ検索Book.objects.filter(author__name="ぼぶ") のように __ でつなぐと、関連先の条件で絞り込めます。

やってみよう

新しい著者を作って本を足したり、aki.book_set.count() で冊数を数えたりしてみましょう。Book.objects.filter(author=aki) のようにオブジェクトを直接条件にもできます。

演習

著者「ぼぶ」に本 Book.objects.create(title="Web開発入門", author=bob) を追加し、bob.book_set.count()(ぼぶの本の冊数)を表示してください。2 になれば成功です。

ヒント1を見る

Book.objects.create(title="Web開発入門", author=bob) を追加します。

ヒント2を見る

print(bob.book_set.count())

実際に動かしてみよう

本文のサンプルや演習のコードは、コードブロック右上の「コピー」ボタンでコピーして、下のエディタに貼り付ければそのまま実行できます。

Python — ライブラリ付きで実行(Pyodide)

numpy / pandas / matplotlib が使える本物のPython(Pyodide)を読み込みます。初回のみ読み込みに少し時間がかかります(以降はブラウザにキャッシュされます)。
スクロールして表示された時点でも自動で読み込まれます。