Django_モデルのForeignKeyとManyToManyを図で理解する #227日目
DjangoではForeignKey (多対一) やManyToMany (多対多) といったフィールドを使って、モデル同士を紐づかせることが可能です。
ただ、私自身いくつか記事を書いてきましたが、ForeignKeyもManyToManyも少しイメージが持ちにくく、いざ使おうとすると「ん?」と混乱しやすいです。
そこでこれらのフィールドのイメージを図で整理して、理解を深められるようにしたいと思います。
ForeignKeyとは
多対一を表すフィールドです。1レコードに対して、他のモデルから1つの値を持たせることができます。以下はそれぞれのプロジェクトに対して1つenterpriseが紐づくようなモデルです。
class Project(models.Model):
enterprise = models.ForeignKey('Enterprise', on_delete=models.CASCADE, related_name='projects')
name = models.CharField(max_length=255, blank=False)
updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
deleted_at = models.DateTimeField(null=True)
users = models.ManyToManyField("User", through='ProjectUser', related_name="projects")
class Enterprise(models.Model):
name = models.CharField(max_length=255, blank=False, unique=True, verbose_name='エンタープライズ名')
business_area = models.CharField(max_length=255, verbose_name='事業分野')
慣れるまでコードだけではイメージしにくいので、図にしてみました。
Project側で【related_name='projects'】と定義しているため、Enterprise側からも逆参照ができるようになっています。
ManyToManyとは
多対多を表すフィールドです。1レコードに対して複数の値を持たせるため、普通の表形式ではデータを持てません。そのため中間テーブルを作ることで多対多を実現します。Djangoでは自動で作成してくれますが、自分で定義することもできます。自分で定義する場合は、中間テーブルにするモデルを「through」引数で指定します。
class Project(models.Model):
enterprise = models.ForeignKey('Enterprise', on_delete=models.CASCADE, related_name='projects')
name = models.CharField(max_length=255, blank=False)
updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
deleted_at = models.DateTimeField(null=True)
users = models.ManyToManyField("User", through='ProjectUser', related_name="projects")
class ProjectUser(models.Model):
project = models.ForeignKey('Project', on_delete=models.CASCADE)
user = models.ForeignKey('User', on_delete=models.CASCADE)
mail_enable = models.BooleanField(default=True)
class User(models.Model):
enterprise = models.ForeignKey('Enterprise', on_delete=models.CASCADE, related_name='users', verbose_name='エンタープライズ')
name = models.CharField(max_length=255, verbose_name='ユーザ名')
password = models.CharField(max_length=255, verbose_name='パスワード')
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新日時')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='作成日時')
これも図にしてみました。
ちなみにForeignKeyで定義した場合、そのモデルには参照先のプライマリーキーのみが表示されます。上記だとProjectのenterprise_idはEnterpriseのpkだけが表示されていて、とエンタープライズ名を取得したい場合は【enterprise_id.name】とします。
また、ManyToManyはテーブルには出てこず、作成された中間テーブルで管理されることになります。
ここまでお読みいただきありがとうございました!!