導入
「著者」と「本」、「ユーザー」と「投稿」。データは互いに関係しています。この「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())。