今回のお題
今回のお題はdjangoアプリにおけるリレーションの実装です。
リレーションと一口にいってもいくつかのバリエーションがありますが、今回はその中でも1対多
のリレーションについてまとめます。
目次
- models.py
- テンプレート
- おまけ〜select_related
- 終わりに
models.py
まずはモデルを用意して、その中に両者の関係性を記述します。
今回は例として書籍のレビューサイトを想定します。
一つの書籍に対して複数のレビューが紐づく可能性があります。
class Book(models.Model):
title = models.CharField(maxlangth=30)
class Review(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
text = models.TextField(max_length=200)
注目すべきは、Reviewモデルの以下の部分ですね。
book = models.ForeignKey(Book, on_delete=CASCADE)
関連するbookインスタンスの情報を保存するためにbook
というフィールドを定義しています。
フィールドの型はForeignKeyで、第一引数は対象となるモデル、on_deleteオプション
はbookインスタンス削除時の挙動です。
今回はon_delete=CASCADE
としているので、あるBookインスタンスが削除されるとそこに紐づくReviewインスタンスも全て削除されます。
以下、その他のon_deleteオプションについて載せておきます。
【PROTECT】
関連するレコードが存在する間は削除ができなくなります。
book = models.ForeignKey(Book, on_delete=models.PROTECT)
# レビューが一つでもある書籍は、先にレビューをレビューを消してからでないと削除できない
【SET_NULL】
関連するレコードが削除されるとNULL
が削除される。
null=True
を設定しておく必要がある。
book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True)
# 関連先の書籍が削除されるとreview.book = nullが自動的に設定される。
【SET_DEFAULT】
関連先のレコード削除時に、あらかじめ決められたデフォルト値を設定する。
defaultオプション
の設定が必須。
book = models.ForeignKey(Book, on_delete=models.SET_DEFAULT, default=xxx)
【SET()】
関連先削除時には、引数として与えた値をセットする。
book = models.ForeignKey(Book, on_delete=models.SET(xxx))
テンプレート
関連先のレコードを取得する際には以下のように記述します。
{# 親モデルから子モデルを取得 #}
{{ book.review_set.all }}
{# 子モデルから親モデルを取得 #}
{{ rev.book }}
親から子を取得する際にはxxx_set.all
とする必要があります。
また、上記のコードはveiwsで用いることも可能です。
おまけ〜select_related
いわゆるN+1問題
を解決するためには、select_related
メソッドを用いるのが便利です。
以下のようにレコード取得の途中でselect_related
メソッドを挟むことで、引数として与えた外部キーの情報を同時に取得することができます。
rev = Review.objects.select_related("book").get(id=pk)
book = rev.book
終わりに
以上が1対多のリレーションの基本になります。
気が向けば多数対多数についてもまとめます。