見出し画像

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はテーブルには出てこず、作成された中間テーブルで管理されることになります。


ここまでお読みいただきありがとうございました!!


参考


この記事が気に入ったらサポートをしてみませんか?