Django OneToOneFieldとForeignKeyの違いとは?

Djangoのモデルで1対1の関係を作成する方法は2つあります。

  • OneToOneFieldを使う
  • ForeignKeyにunique=Trueを設定して使う

どちらの1対1の関係を作成できますが、リレーションの「逆」側の扱いが異なります。

今回は、OneToOneFieldとForeignKey(unique=True)の違いを解説します。

OneToOneField

例としてRestaurantクラスを作成します。RestaurantとUserクラスが1対1の関係です。

from django.db import models
from django.contrib.auth.models import User


class Restaurant(models.Model):
    owner = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
    )

OneToOneFieldを使ったの場合、Userクラスのオブジェクトから、Restaurantクラスのオブジェクトに直接アクセスできます。

OneToOneFieldを書いたクラスのオブジェクトにアクセスするには、小文字に変換したクラス名を使います。(related_nameというキーワード引数で変更することも可能です。)

例えば下記の様に、user.restaurantとかけば、userオブジェクトと1対1の関係にあるRestaurantオブジェクトにアクセスできます。

user = User.objects.get(id=1)
restaurant = Restaurant(owner = user)
restaurant.save()

print(restaurant == user.restaurant) # True

OneToOneFieldの方を使った方がコードが明解になり、おすすめです。

ForeignKey

次は、ForeignKeyを使ってRestaurantクラスを作成した例です。

from django.db import models
from django.contrib.auth.models import User


class Restaurant(models.Model):
    owner = models. ForeignKey(
        User,
        on_delete=models.CASCADE,
        unique=True,
    )

ForeignKeyを使った場合、UserクラスのオブジェクトからRestaurantクラスのオブジェクトにアクセスする場合は、classname_setを使います。

classnameには参照元のクラス名を小文字に変換した名前が入ります。上記の場合は、restaurant_setです。

user = User.objects.get(id=1)
restaurant = Restaurant(owner = user)
restaurant.save()

users_restaurants = user.restaurant_set.all()

print(restaurant == users_restaurants[0]) # True

unique=Trueを設定して1対1の関係にしても、参照先→参照元へのアクセスは1対多の時と同じです。

基本的にはuser.restaurant_set.all() の様に、関連するオブジェクトのクエリセットを取得した後、1つ目の要素にアクセスする書き方になります。

まとめ

OneToOneFieldとForeignKey(unique=True)の違いは、リレーションの「逆」側の扱いが異なることです。

OneToOneFieldの方を使った方がコードが明解になるのでおすすめです。

スポンサーリンク
スポンサーリンク