Django 1.5の新しい 構成可能なユーザーモデル 機能を使用して複数のユーザータイプを実装するための推奨される方法は何ですか?
プライベートユーザーとトレードユーザーの2つのユーザータイプがあり、それぞれに独自の必須フィールドのセットがあります。
これを実装するために私が考えることができる2つの方法があります:
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)
# ...
構成可能なユーザーモデルと組み合わせてマルチテーブル継承を使用することに問題はありますか?
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の場合、ユーザーをフィルタリングするにはどうすればよいですか?
ありがとう。
警告: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による 優れたブログ投稿 があります。
とはいえ、各アプローチの長所と短所、およびプロジェクトへの影響を考慮する必要があります。関連するロジックが小さい場合(説明した例のように)、両方のアプローチが有効です。しかし、より複雑なシナリオでは、アプローチは他のアプローチよりも優れている可能性があります。より拡張性があるため、マルチモデルオプションを選択します。
たぶんあなたはAbstractUserを検討する必要がありますか?
AUTH_USER_MODELに割り当てることができる新しいカスタムユーザーモデルは1つだけです。マルチテーブル継承では、2つのモデルがあります。それが問題です。
両方のユーザータイプをカバーする単一のユーザーモデルの場合、モデルメソッドの条件付きロジックを抽象化できます。また、ユーザータイプの違いに基づいて、ユーザータイプごとに異なるマネージャーを使用することもできます。これは、特定のユーザータイプを操作するときに明示的にするのにも役立ちます。
他のオプションは、最も一般的な属性のみを単一のユーザーモデルに格納し、2つのユーザータイプの詳細をメインユーザーテーブルにリンクされている独自のテーブルにアタッチすることです。
両方のユーザーが(少なくともデータに関して)ほとんどの共通点を持っている場合、私はそれらを1か所に保管します。結局、私は何がより簡単で維持しやすいかについて考えるでしょう。
「type」属性を持つ単一のモデルを使用します。理由は次のとおりです。