37

Django 1.5の新しい構成可能なユーザーモデル機能を使用して複数のユーザータイプを実装するための推奨される方法は何ですか?

プライベートユーザーとトレードユーザーの2つのユーザータイプがあり、それぞれに独自の必須フィールドのセットがあります。

これを実装するために私が考えることができる2つの方法があります:

1)マルチテーブル継承

class BaseUser(AbstractBaseUser):
  email = models.EmailField(max_length=254, unique=True)
  # ...


class PrivateUser(BaseUser):
  first_name = models.CharField(max_length=30)
  last_name = models.CharField(max_length=30)
  # ...


class TradeUser(BaseUser):
  company_name = models.CharField(max_length=100)
  # ...

構成可能なユーザーモデルと組み合わせてマルチテーブル継承を使用することに問題はありますか?

2)「type」属性を持つ単一のモデルを使用する

class User(AbstractBaseUser):
  email = models.EmailField(max_length=254, unique=True)
  user_type = models.CharField(max_length=30, choices={
    'P': 'Private',
    'T': 'Trade',
  })
  first_name = models.CharField(max_length=30, blank=True)
  last_name = models.CharField(max_length=30, blank=True)
  company_name = models.CharField(max_length=100, blank=True)
  # ...

この方法では、に依存する条件付き検証が必要になりますuser_type

これらの方法のどれが私のユースケースに最も適していますか?それとも、これを達成するためのより良い方法がありますか?

また、ケース番号1の場合、ユーザーをフィルタリングするにはどうすればよいですか?

ありがとう。

4

4 に答える 4

29

警告:Django 1.5は非常に新しく、人々はまだその新機能を調査しています。したがって、この質問に答えるための最近の調査に基づく私の答えは、私の意見にすぎません。

どちらの方法も、結果を達成するための有効な方法であり、長所と短所があります。

まず始めましょう:

2番目のオプション

  • ネストされたモデルがなく、モジュール式ではありません。AbstractBaseUser、名前が示すように、抽象モデルであり、特定のテーブルはありません
  • 未使用のフィールドがあります
  • 追加のフィールドを使用するモデルでの反復について、user_typeを確認する必要があります。

    def foo():
        if user.user_type == 'Private':
            # ...
        else:
            # ...
    

結果のSQLはおおよそ次のようになります。

CREATE TABLE "myapp_user" (
    "id" integer NOT NULL PRIMARY KEY,
    "password" varchar(128) NOT NULL,
    "last_login" datetime NOT NULL,
    "email" varchar(254) NOT NULL UNIQUE,
    "user_type" varchar(30) NOT NULL,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL,
    "company_name" varchar(100) NOT NULL
);

最初のオプション

  • エンティティが論理的に分離されたネストされたモデル
  • 非常に無駄がない
  • のような関数を使用する場合はBaseUserManager、子ごとに実装する必要があります create_user
  • BaseUser.objects.all()単純な*でサブクラスにアクセスすることはできません

結果のSQLはおおよそ次のようになります。

CREATE TABLE "myapp_baseuser" (
    "id" integer NOT NULL PRIMARY KEY,
    "password" varchar(128) NOT NULL,
    "last_login" datetime NOT NULL,
    "email" varchar(254) NOT NULL UNIQUE
);

CREATE TABLE "myapp_privateuser" (
    "baseuser_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "myapp_baseuser" ("id"),
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

CREATE TABLE "myapp_tradeuser" (
    "baseuser_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "myapp_baseuser" ("id"),
    "company_name" varchar(100) NOT NULL
);

*次の状況を想像してみてください。

>>> BaseUser.objects.create_user('baseuser@users.com', password='baseuser')
>>> PrivateUser.objects.create_user('privateuser@users.com', password='privateuser', first_name='His', last_name='Name')
>>> TradeUser.objects.create_user('tradeuser@users.com', password='tradeuser', company_name='Tech Inc.')
>>> BaseUser.objects.all()
[<BaseUser: baseuser@users.com>, <BaseUser: privateuser@users.com>, <BaseUser: tradeuser@users.com>]
>>> PrivateUser.objects.all()
[<PrivateUser: privateuser@users.com>]
>>> TradeUser.objects.all()
[<TradeUser: tradeuser@users.com>]

したがって、を使用してサブクラスインスタンスを直接取得することはできませんBaseUser.objects.all()ジェフによる優れたブログ投稿があり、その子から「自動ダウンキャスト」を実現する方法をよりよく説明してBaseUserいます。

とはいえ、各アプローチの長所と短所、およびプロジェクトへの影響を考慮する必要があります。関連するロジックが小さい場合(説明した例のように)、両方のアプローチが有効です。しかし、より複雑なシナリオでは、アプローチは他のアプローチよりも優れている可能性があります。より拡張性があるので、マルチモデルオプションを選択します。

于 2012-12-06T21:48:43.103 に答える
6

たぶんあなたはAbstractUserを検討する必要がありますか?

于 2013-01-24T13:11:24.683 に答える
2

AUTH_USER_MODELに割り当てることができる新しいカスタムユーザーモデルは1つだけです。マルチテーブル継承では、2つのモデルがあります。それが問題です。

両方のユーザータイプをカバーするシングルユーザーモデルの場合、モデルメソッドの条件付きロジックを抽象化できます。また、ユーザータイプの違いに基づいて、ユーザータイプごとに異なるマネージャーを使用することもできます。これは、特定のユーザータイプを操作するときに明示的にするのにも役立ちます。

他のオプションは、最も一般的な属性のみを単一のユーザーモデルに格納し、次に2つのユーザータイプの詳細をメインユーザーテーブルにリンクされている独自のテーブルにアタッチすることです。

両方のユーザーが(少なくともデータに関して)ほとんどの共通点を持っている場合、私はそれらを1つの場所に保持します。結局、私は何がより簡単で維持しやすいかについて考えます。

于 2012-12-06T20:59:43.327 に答える
1

「type」属性を持つ単一のモデルを使用します。理由は次のとおりです。

  • 1つのテーブル、1つのモデルのみ
  • あるタイプから別のタイプに変換する場合は、属性を変更するだけです
  • あるタイプには存在し、他のタイプには存在しないフィールドにゲッターとセッターを実装する=はるかに簡単に使用できます。
于 2013-04-19T13:32:57.133 に答える