web-dev-qa-db-ja.com

Django 1.5で複数のユーザータイプを実装する

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の場合、ユーザーをフィルタリングするにはどうすればよいですか?

ありがとう。

37
gjb

警告: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('[email protected]', password='baseuser')
>>> PrivateUser.objects.create_user('[email protected]', password='privateuser', first_name='His', last_name='Name')
>>> TradeUser.objects.create_user('[email protected]', password='tradeuser', company_name='Tech Inc.')
>>> BaseUser.objects.all()
[<BaseUser: [email protected]>, <BaseUser: [email protected]>, <BaseUser: [email protected]>]
>>> PrivateUser.objects.all()
[<PrivateUser: [email protected]>]
>>> TradeUser.objects.all()
[<TradeUser: [email protected]>]
_

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

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

29
borges

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

6
Robert

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

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

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

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

2
maulik13

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

  • 1つのテーブル、1つのモデルのみ
  • あるタイプから別のタイプに変換したい場合は、属性を変更するだけです
  • あるタイプには存在し、他のタイプには存在しないフィールドにゲッターとセッターを実装する=はるかに使いやすい。
1