【django】モデルのリレーションフィールド:ForeignKey、OneToOneField、ManyToManyField

時計 2021.06.13 / 時計

【django】モデルのリレーションフィールド:ForeignKey、OneToOneField、ManyToManyField

本記事ではdjangoのモデルにおける、リレーションフィールドForeignKey、OneToOneField、ManyToManyField)について詳しく解説していきます。

djangoのデータベースで複数のモデルを扱う際、リレーションフィールドを用いてそれぞれのモデルを関係付けしていきます。

Webアプリケーション開発でデータベースを扱うことは必須です。
djangoでデータベースを操作するには、モデルmodelを使います。

Modelモデルの定義についての基本は、以下記事をご参照ください。

モデルを定義する際にフィールドを定義します。
フィールドの型やフィールドオプションについては、以下記事をご参照ください。

そのフィールド定義でリレーションフィールドという手法を使います。

ぜひ本記事でリレーションフィールドについて理解を深めてください。

リレーションフィールド

複数のモデル間(テーブル間)を紐づけるためにリレーションフィールドという手法を用います。

リレーションフィールドには次に示す3種類が用意されています。

リレーションフィールド 関係性
ForeignKey 多対一
OneToOneField 一対一
ManyToManyField 多対多

ForeignKey:外部キー

リレーションフィールドForeignKeyは、他モデルと多対一のリレーションを持つフィールドを作成します。

ForeignKeyを用いることで、そのフィールドのモデルを別モデル(テーブル)と紐づけます。

つまり「多対一」の関係を持つ2つの異なるモデルを結びつけるためにForeignKeyでフィールドを作成するということです。

ForeignKey(to, on_delete, **options)

ForeignKeyには2つの引数(to, on_delete)を必ず指定する必要があります。
toには紐づけるモデルを指定し、on_deleteには親フィールドが削除されたときの動作を指定します。

「1」になるモデルが親、「多」になるモデルが子の関係となります。
ForeignKeyのフィールドは子側に作成します。

例としては、Departmentという部署モデルとPersonという人モデルがあった場合、Departmentが「1」、Personが「多」となります。
なぜなら、1つの部署には多くの人が属しており、1人の人は1つの部署に属しているからです。

これを図で表すと次のようになります。

django:モデルのForeignフィールドの関係

その他にもブログの投稿者(一)とブログ記事(多)の関係や、学校のクラブ(一)と生徒(多)の関係などがあります。

models.py

DepartmentとPersonの各モデルがmodels.pyでは、次のようになります。

from django.db import models

class Department(models.Model):
    department_name = models.CharField(max_length=255)

    def __str__(self):
        return self.department_name

class Person(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    department = models.ForeignKey(Department, on_delete=models.CASCADE)

関連先のモデルを参照する

ForeignKeyによって関連を持ったモデル間で相手モデルのフィールドを参照することができます。

例えばUserモデル(ForeginKey:department)からDepartmentモデル(親)を参照するには次のように記述します。

>>> obj = User.objects.get(id=1)
>>> obj.department

ForeignKeyのフィールドが定義されていない側のモデルから、ForeignKeyが定義されているモデルを参照(逆参照)する方法については以下記事をご参照ください。

OneToOne

リレーションフィールドOneToOneは、他モデルと一対一のリレーションを持つフィールドを作成します。

OneToOneを用いることで、そのフィールドのモデルを別モデル(テーブル)と紐づけます。

つまり「一対一」の関係を持つ2つの異なるモデルを結びつけるためにOneToOneでフィールドを作成するということです。

OneToOneField(to, on_delete, parent_link=False, **options)

OneToOneFieldはForeignKeyにオプションunique=Trueにしたようなフィールドです。

例としてはショッピングサイトで、利用者UserモデルとショッピングカートCartモデルが一対一の関係となります。

models.py

UserとCartの各モデルがmodels.pyでは、次のようになります。

from django.db import models

class User(models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)

    def __str__(self):
        return self.first_name

class Cart(models.Model):
    user = models.OneToOneField(User, related_name=”user_cart”)

ManyToMany

リレーションフィールドManyToManyは、他モデルと多対多のリレーションを持つフィールドを作成します。

ManyToManyを用いることで、そのフィールドのモデルを別モデル(テーブル)と紐づけます。

つまり「多対多」の関係を持つ2つの異なるモデルを結びつけるためにManyToManyでフィールドを作成するということです。

例としては、Personモデルと趣味を保持するHobbyモデルが多対多の関係となります。
一人が複数の趣味を持つこともありますし、一つの趣味が複数の人に持たれているので多対多となります。

models.py

PersonとHobbyの各モデルがmodels.pyでは、次のようになります。

from django.db import models

class Hobby(models.Model):
    hobby_name = models.CharField(max_length=255)

class Person(models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    hobbys = models.ManyToMany(Hobby, blank=True)

    def __str__(self):
        return self.first_name

フィールドオプション

on_deleteオプション(OneToOneField、ForeignKey)

フィールドオプションon_deleteによって、紐づいている親フィールドのレコードが削除された場合の、子フィールドの動作を指定できます。

on_deleteが使えるフィールドの型はForeignKeyとOneToOneFieldのみです。

on_deleteで指定できる値は次のようになります。

on_delete 意味
models.CASCADE 親データが削除されると結びついている子データも削除される
models.PROTECT 結びついている子データがある場合は親データを削除できない
models.SET_NULL 親データが削除されると子データにNullをセットする
models.SET_DEFAULT 親データが削除されると子データにデフォルト値をセットする
models.DO_NOTHING 親データが削除されても何もしません

related_nameオプション

related_nameオプションは、指定した名前で逆参照(1側のモデルから多側のモデルを参照)できるようにしたい場合に使用します。

to_field

紐づけるモデルのフィールドを指定できます。

category = models.ForeignKey(‘Category’, to_field=’category_id’, on_delete=models.SET_NULL, null=True)

まとめ

本記事「【django】モデルのリレーションフィールド:ForeignKey、OneToOneField、ManyToManyField」はいかがでしたか。

Webアプリケーションで複数のモデル(テーブル)を扱う場合、リレーションフィールドはほぼ必須の知識です。

中規模または大規模なシステムの開発ができるように、モデル・モデルの型・オプション・リレーションフィールドを本サイトを通してマスターしてください。