ManyToMany Field を使ったモデル
多対多(n対n)で紐づくモデルの設計方法は以前の投稿で書きました。
今回は、ManyToManyField で自動生成される中間テーブルをあえて自分で作成して、独自の中間フィールドを追加して動かすまでを備忘録として残します。
中間テーブルの手動生成
以前のモデルを利用します。
本来は ManyToMany を設定しただけで中間テーブルが自動で生成されるのですが、それだと独自に中間フィールドを設けられないので、手動で中間テーブルを作成します。
以下のようにコードを追加します。
model.py
from django.db import models
class Publication(models.Model):
"""
出版物モデル
"""
title = models.CharField(max_length=30)
class Meta:
ordering = ['title']
def __str__(self):
return self.title
class Article(models.Model):
"""
記事モデル
"""
headline = models.CharField(max_length=100)
# ↓ここで多対多の設定
publications = models.ManyToManyField(
Publication,
related_name="articles",
through="PublicationArticleRelation", # ←中間テーブル名の指定を追加
)
class Meta:
ordering = ['headline']
def __str__(self):
return self.headline
# ここから中間テーブルの定義(追加)
class PublicationArticleRelation(models.Model):
"""
出版物と記事の中間モデル
"""
publication = models.ForeignKey(
Publication,
related_name="publication_relation",
verbose_name="出版物",
on_delete=models.CASCADE,
)
article = models.ForeignKey(
Article,
related_name="article_relation",
verbose_name="記事",
on_delete=models.CASCADE,
)
# 独自の中間フィールド
thema = models.CharField(
"テーマ", max_length=16,
)
articleモデルの ManyToManyField のthrough引数と、ソース後半の中間テーブル定義の部分を追加しています。
操作してみる
リレーションの作成例
p1 = Publication.objects.get(id = 1)
a1 = article.objects.get(id = 1)
PublicationArticleRelation.objects.create(
publication = p1,
articke = a1,
thema = "音楽"
)
このように、基本的には普通のモデルと同じように扱うことができる。
上記で作成したリレーションを呼び出すときは以下のようにすれば良い。
# 出版物がp1のリレーション
PublicationArticleRelation.objects.get(publication = p1)
# 記事がa1のリレーション
PublicationArticleRelation.objects.get(article = a1)
# テーマが音楽のリレーション
PublicationArticleRelation.objects.get(thema = "音楽")
# 出版物がp1かつ記事がa1かつテーマが音楽のリレーション
PublicationArticleRelation.objects.get(publication = p1, article = a1, thema = "音楽")