web-dev-qa-db-ja.com

Django:Userを拡張するときは、OneToOneField(User)またはForeignKey(User、unique = True)を使用する方が良いですか?

Djangoユーザーモデルを拡張して、UserProfileモデルを作成するときに、OneToOneField(User)ForeignKey(User, unique=True)のどちらを使用するかについて矛盾する情報を見つけています。

これを使用する方が良いですか?:

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)

またはこれ?:

class UserProfile(models.Model):
    user = models.OneToOneField(User)

Django DocOneToOneFieldを指定し、 Django Bookの例ForeignKeyを使用します。

James Bennett には、矛盾する例を提供する2つのブログ投稿もあります。

前の投稿で、ベネットはForeignKeyの代わりにOneToOneFieldを使用するように切り替えた理由をいくつか説明していますが、特に反対を推奨する他の投稿を見ると、私はそれを完全には理解していません。

私はあなたの好みとその理由を知りたいです。または、それも重要ですか?

29
Tony Guinta

この記事に記載されている唯一の本当の理由は、Userの管理ページにUserUserProfileの両方のフィールドが表示されるように設定できることです。これは、少量のエルボーグリースを使用したOneToOneFieldで複製できるため、管理ページに表示することに夢中になっている場合を除いて、少しわかりやすくする必要があります(「ユーザー?!ああ、いや、待って、それはユニークに設定されています。 ")私はOneToOneFieldを使います。

管理ページのインラインに加えて、ForeignKeyソリューションの他の理由は、オブジェクトが逆の関係でアクセスされるときに、正しいデフォルトのDBマネージャーを使用できることです。この例を考えてみましょう サブクラスマネージャースニペット 。例のPostクラス定義が次のようになっているとしましょう。

_class Post(ParentModel):
    title = models.CharField(max_length=50)
    onetoone = models.ForeignKey(SomeModel, unique=True)

    children = ChildManager()
    objects = models.Manager()
_

somemodel_instance.post_set.all()[0]を呼び出すことにより、最初の(デフォルトの)マネージャーをPostとして定義することで示されるように、ChildManagerクラスの目的のサブクラスオブジェクトを取得します。一方、OneToOneFieldでは、_somemodel_instance.post_を呼び出すことにより、Postクラスインスタンスを取得します。いつでも_somemodel_instance.post.subclass_object_を呼び出して同じ結果を得ることができますが、デフォルトのマネージャーは他の種類のトリックを実行でき、FKソリューションはそれらをうまく隠します。

カスタムマネージャーコードを所有していて変更できる場合は、正当な1to1フィールドの代わりにFKを使用する代わりに、 _use_for_related_fields_ 属性を使用できますが、それでも、不明な点があるために失敗する可能性があります。自動管理者の迷惑です。私が覚えている限り、上記の例では失敗します。

7
trybik

逆関係に関連するOneToOneFieldを一般的に使用しないその他の理由:OneToOneFieldを介して定義された逆関係を使用すると、Manager逆関係のForeignKeyとは対照的に、モデルインスタンスが取得され、その結果、常にDBヒットが発生します。これは、(_meta.get_all_related_objects()を介して)逆の関係でいくつかの一般的なことを行い、それらをすべて使用するかどうかわからない場合はコストがかかります。

5
trybik