OneToOneFieldを使うと関連モデルから属性へアクセス出来るようになる

www.youtube.com

Multiple User Types With Custom Data Fields | Djangoという動画中に出てくるコードを見て、自分にとっては謎の挙動だったので調べました。

具体的には以下のようなコードが動画中で書かれていました。

class DriverMore(User):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    model = models.CharField(max_length=255)
    make = models.CharField(max_length=255)
    year = models.IntegerField()


class Driver(User):
    base_type = User.Types.DRIVER
    objects = DriverManager()

    @property
    def more(self):
        return self.drivermore

疑問点としては、この中のDrivermoreが「なぜDriverとは別のDriverMoreクラス」に対してアクセス出来るようになっているのか分かりませんでした。

理由について

Djangoの公式リファレンスによると、以下の記述がありました。

Assuming an existing Employee Fred Smith who has both a User and Employee model, you can access the related information using Django's standard related model conventions:

Djangoの挙動によって関連づけられ、アクセスできるということが分かりました(実際にはUserとEmployee model の例が一緒に書かれているので後半部分の記述が主な理由です)。

https://docs.djangoproject.com/ja/5.0/topics/auth/customizing/#extending-the-existing-user-model

手元でも書いてみたサンプルコード

例えば、以下のようなコードがあるとします。

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


class More(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    address = models.TextField()
    postal_code = models.CharField(max_length=7)

そして、以下のようなコードをmanage.py shell コマンドで実行してみます。

from django.contrib.auth.models import User
nibu = User.objects.create_user(username="nibu", email="nibu@example.com", password="nibu")

from drivers.models import More
nibu_more = More(user=nibu, address="住所", postal_code="0123456")

nibu.more.address  # 住所
nibu.more.postal_code  # 0123456

この挙動から、変数nibu、すなわちUserクラスにはmoreという属性は本来はありませんが、OneToOneFieldを利用したことでmoreにアクセス出来る事が自身の手を動かしてみても確認できました。

また、反対にmoreから辿ることも出来ました。

nibu_more.user  # <User: nibu>
nibu_more.user.username  # nibu
nibu_more.user.email  # nibu@example.com

最初、Pythonは同じファイルに書いたクラスにアクセス出来るんだっけ・・・?と驚いたが、Djangoの特性?によるものだったのでまだまだ知らない挙動がありそうだなと実感しています。

補足

ちなみに、こういうModelはProfile modelと呼ばれているそうです。

https://docs.djangoproject.com/en/5.0/topics/auth/customizing/#extending-the-existing-user-model

より以下の記述がありました。

This one-to-one model is often called a profile model

認証情報以外のユーザーに関連するデータを保持する、というのは良くあるケースと聞いて、確かにそうだな、と感じました。

そして、自社の自走プログラマーにも以下のようなページがあることを教えてもらって、自走プログラマーの内容を理解していたらもっと早く理解できていたのだろう、と思いました・・・。

51:参照頻度が低いカラムはテーブルを分ける