18

これがすべて理にかなっていることを願っています:)必要に応じてコメントで明確にします。また、私はこの質問で太字のテキストを使用して実験しており、私(またはあなた)が気が散る場合はそれを編集します。それが邪魔にならないように...

django.contrib.authを使用すると、ユーザーとグループが提供されます。基本的なメッセージングなど、これなしでは実行できない便利な機能もあります。

私のアプリには、いくつかの異なるタイプのユーザーがいます。ユーザーは1つのタイプのみになります。それは、少し特別な注意を払えば、グループによって簡単に処理されます。ただし、これらの異なるユーザーは、階層/関係で相互に関連しています。

これらのユーザーを見てみましょう:-

プリンシパル-「トップレベル」ユーザー

管理者-各管理者はプリンシパルに報告します

コーディネーター-各コーディネーターは管理者に報告します

これらとは別に、直接関連していないが、後で関連する可能性のある他のユーザータイプがあります。たとえば、「会社」は別のタイプのユーザーであり、さまざまな「製品」を持つことができ、製品は「コーディネーター」によって監督される場合があります。「バイヤー」は、製品を購入する可能性のある別の種類のユーザーです。

現在、これらすべてのユーザーには他のさまざまな属性があり、その一部はすべてのタイプのユーザーに共通であり、一部は1つのユーザータイプにのみ固有です。たとえば、すべてのタイプのユーザーはアドレスを持っている必要があります。一方、「BranchOffice」に属するのはプリンシパルユーザーのみです。

上で述べたもう1つのポイントは、ユーザーは1つのタイプにしかなれません

アプリは、プリンシパル、管理者、コーディネーター、会社、製品などを誰が作成および/または変更したかを追跡する必要もあります。(つまり、ユーザーモデルへのリンクがあと2つあります。)

このシナリオでは、Djangoのマルチテーブル継承を次のように使用することをお勧めします。

from django.contrib.auth.models import User
class Principal(User):
    #
    #
    #    
    branchoffice = models.ForeignKey(BranchOffice)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalcreator")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalmodifier")
    #
    #
    #

または、このように実行する必要があります:-

class Principal(models.Model):
    #
    #
    #
    user = models.OneToOneField(User, blank=True)
    branchoffice = models.ForeignKey(BranchOffice)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalcreator")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalmodifier")
    #
    #
    #

外部キーを介して関連する他のユーザータイプがあることに注意してください。例:-

class Administrator(models.Model):
    #
    #
    #
    principal = models.ForeignKey(Principal, help_text="The supervising principal for this Administrator")
    user = models.OneToOneField(User, blank=True)
    province = models.ForeignKey(         Province)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="administratorcreator")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="administratormodifier")

Djangoは、舞台裏でマルチテーブル継承に1対1の関係を使用していることを認識しています。私はどちらがより健全なアプローチであるかを決定するのに十分な資格がありません。

4

5 に答える 5

17

@thornomad によるソリューションを拡張したいと思います。

Django の User クラスを直接拡張すると、内部の django.auth メカニズムであらゆる種類の問題が発生する可能性があります。同様の状況で私が行ったことは、まさに@thornomadが示唆することです-私はDjangoユーザーモデルと1対1でリンクされた独自のUserProfileモデルを作成しました。そこには追加のユーザーデータが保持され、そこからさまざまなタイプのモデルを継承しましたユーザーの。

あなたが説明したものに合うもの:

class UserProfile(models.Model):
    user = models.OneToOneField(User, blank=True, related_name='profile')
    class Meta:
        abstract = True


class PositionHolderUserProfile(UserProfile):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(PositionHolderUserProfile, editable=False, blank=True, related_name="created_users")    
    modified_by = models.ForeignKey(PositionHolderUserProfile, editable=False, blank=True, related_name="modified_users")

class Principal(PositionHolderUserProfile):
    branchoffice = models.ForeignKey(BranchOffice)

class Administrator(PositionHolderUserProfile):
    superior = models.ForeignKey(Principal, related_name="subordinates")
    province = models.ForeignKey(Province)

class Coordinator(PositionHolderUserProfile):
    superior = models.ForeignKey(Administrator, related_name="subordinates")


class Company(UserProfile):
    name = models.CharField(max_length=50)

class Product(models.Model):
    name = models.CharField(max_length=50)
    produced_by = models.ForeignKey(Company)

class Buyer(UserProfile):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    products_bought = models.ManyToManyField(Product)
于 2009-12-05T13:07:04.527 に答える
3

最近、contrib.auto.models.Userを継承するモデルの使用に切り替えました。私の一般的な見解では、理論的には優れていますが、想定どおりに自動的に処理されない場合があります。

継承とOneToOneに関するあなたの決定は、次のようになります。

  • Djangoに95%の確率で自動的に何かを実行させ、他の5%をデバッグする必要がありますか?

-また-

  • 100%自分で手動で何かをしたいですか

まだご覧になっていない場合は、Scott Barhamブログに、Userの継承と、カスタムオブジェクトが返されることを確認するためのカスタムバックエンドの構築に関するすばらしい投稿があります-DjangoUserの拡張

さらに興味深いのは、 django- annoyingによって提供されるAutoOneToOneフィールドです。これは、ここでは2つのアプローチのハイブリッドのようなものです。継承は行われませんが、Djangoは、一致するOneToOneFieldが存在しない場合は、それを作成します。

また、thornomadは、モデルの冗長性について良い点を示しています。抽象クラスを簡単に実装して、それをクリーンアップすることができます(手動のOneToOneを実行していると仮定します)。

class BaseExtendedUser(models.Model):
    user = models.OneToOneField(User, blank=True, related_name='profile')
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="created_users")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="modified_users")

    class Meta:
        abstract = True

class Administrator(BaseExtendedUser):
    province = models.ForeignKey(Province)

class Principal(BaseExtendedUser):
    branchoffice = models.ForeignKey(BranchOffice)
于 2009-11-25T16:25:51.997 に答える
2

モデルを継承するのではなく、モデルをそのままにUserしてカスタムを使用すると思います。カスタムモデルを使用すると、さまざまなユーザー タイプすべての一部となる基本ユーザー プロファイル モデルをセットアップできます。UserProfilecontrib.authUserProfile

それをすばやく見るだけでも、同じフィールドをすべて繰り返すモデルを注意深く調べます (最後の 2 つのモデルPrincipleAdministratorモデルのように)。組み込みのグループ機能をユーザー プロファイルのアイデアと組み合わせると、探していることができる場合があります。

于 2009-11-25T12:36:48.610 に答える
0

どこでもauth.Userのように機能するために、ユーザークラスのオブジェクトが必要ですか?これが、OneToOneよりも継承を使用する最も明白な理由です。OneToOneアプローチの利点の1つは、懸念がある場合に、別のユーザーモデルに簡単に切り替えることができることです。

上記の(どちらの方法でも)実際の問題は、PrincipalオブジェクトとAdministratorオブジェクトが同じユーザーを共有することを妨げるものが何もないように見えることです。OneToOneFieldは、任意の2つのリレーション間の1対1のマッピングのみを保証できます。

于 2009-12-04T18:20:28.900 に答える
0

コーディネーターがプリンシパルに昇格したとき、データ モデルで何が起こるかを考えてください。この場合、継承はまったく使用しません。以前の投稿者の提案「組み込みのグループ機能とユーザー プロファイルのアイデアを組み合わせることで、探していることが実現する可能性がある」という提案を再考してください。

于 2009-11-29T11:53:05.747 に答える