10

注:django.contrib.authが気に入らないと言って、この質問に「答える」誘惑に駆られた場合は、先に進んでください。それは役に立ちません。私はこの問題に関する意見の範囲と強さをよく知っています。

さて、質問:

慣例では、OneToOnetoUserを使用してモデルUserProfileを作成します。

私が考えることができるあらゆる方法で、より効率的で効果的なアプローチは、ユーザーをシステム内のすべての人間に使用する予定のクラス(たとえば、Person(User)と呼ばれるクラス)にサブクラス化することです。

前者が従来型であり、後者がハックと見なされる理由についての首尾一貫した説明を見たことがありません。少し前に、get_profile()を使用できるようにするために、OneToOneアプローチに切り替えましたが、それ以来、後悔しています。このアプローチの利点を理解させることができない限り、私は元に戻すことを考えています。

4

3 に答える 3

4

モデルのサブクラス化が内部で OneToOne 関係によって実装されていることを認識していますか? 実際、効率に関する限り、これら 2 つの方法に違いはまったく見られません。

私の意見では、既存の具象モデルのサブクラス化は厄介なハックであり、可能であれば避けるべきです。余分なデータベースアクセスがいつ実行されるかが不明確になるように、データベースの関係を隠す必要があります。リレーションシップを明示的に示し、必要に応じて明示的にアクセスする方がはるかに明確です。

さて、私が気に入っている 3 番目の方法は、完全に新しい User モデルを作成し、デフォルトのモデルの代わりに新しいモデルのインスタンスを返すカスタム認証バックエンドを作成することです。バックエンドを作成するには、いくつかの単純なメソッドを定義するだけなので、非常に簡単です。

于 2011-03-27T20:56:54.410 に答える
2

少なくとも「公式の」情報源からは、実際には、Userのサブクラス化がUserProfileを持つよりも役に立たない理由について、実際に良い説明はありませんでした。

ただし、いくつかの理由があります。それは、ユーザーのサブクラス化が「進むべき道」であると自分自身で判断した後に思いついたものです。

  • カスタム認証バックエンドが必要です。これは大きな問題ではありませんが、記述する必要のあるコードが少ないほど良いです。
  • 他のアプリは、ユーザーがであると想定している可能性がありますdjango.contrib.auth.models.User。そのコードがユーザーオブジェクトをフェッチしていない限り、ほとんどの場合、これは問題ありません。私たちはサブクラスであるため、Userオブジェクトを使用するコードであれば問題ありません。
  • ユーザーは、一度に1つのサブクラスにしか「なれません」。たとえば、StudentとTeacherのUserサブクラスがある場合、特定の時点で、UserはTeacherまたはStudentにしかなれません。UserProfilesを使用すると、同じユーザーに同時に教師と生徒の両方のプロファイルを添付できます。
  • 続いて、あるサブクラスから別のサブクラスへの変換は困難です。特に、あるサブクラスのインスタンスがすでにある場合はなおさらです。

したがって、「私のプロジェクトには1つのUserサブクラスしかありません」と言うかもしれません。私もそう思っていました。これで、3人に加えて、通常のユーザー、場合によっては4人目のユーザーがいます。要件が変更され、それに対処するためにコードのヒープを変更する必要があるのはそれほど楽しいことではありません。

注:最近、contrib.authユーザーモデルに関連する問題のより良い修正について、django-developersについてかなり多くの議論がありました。

于 2012-07-10T03:51:59.207 に答える
0

User モデルを継承した方が効率的で効果的ですか? 理由はわかりませんが、あなたの主張を読みたいです。IMNSHO、モデルの継承は常に苦痛でした。

それでも、これはあなたの質問に答えないかもしれませんが、このスニペットで Will Hardy によって提案された解決策には非常に満足しています。シグナルを利用して、新しいユーザーごとに新しいユーザー プロファイルを自動的に作成します。

リンクが消えることはまずありませんが、彼のコードの私のわずかに異なるバージョンは次のとおりです。

from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _

class AuthUserProfileModelBase(models.base.ModelBase):
    # _prepare is not part of the public API and may change
    def _prepare(self):
        super(AuthUserProfileModelBase, self)._prepare()
        def on_save(sender, instance, created, **kwargs):
            if created:
                self.objects.create(user=instance)
        # Automatically link profile when a new user is created
        post_save.connect(on_save, sender=User, weak=False)

# Every profile model must inherit this class
class AuthUserProfileModel(models.Model):
    class Meta:
        abstract = True
    __metaclass__ = AuthUserProfileModelBase
    user = models.OneToOneField(User, db_column='auth_user_id',
        primary_key=True, parent_link=True)

# The actual profile model
class Profile(AuthUserProfileModel):
    class Meta:
        app_label = 'some_app_label'
        db_table = 'auth_user_profile'
        managed = True
    language = models.CharField(_('language'), max_length=5, default='en')

もちろん、功績はすべてウィル・ハーディにあります。

于 2011-03-27T21:37:25.447 に答える