37 votes

Implémentation de plusieurs types d'utilisateurs avec Django 1.5

Quelle est la méthode recommandée pour mettre en œuvre plusieurs types d'utilisateur à l'aide de Django 1.5 nouveau configurable par l'utilisateur du modèle de la fonctionnalité?

Je voudrais avoir deux types d'utilisateurs: les utilisateurs privés et les utilisateurs commerciaux, chacun avec leur propre ensemble de champs obligatoires.

Il ya deux façons que je peux penser pour mettre en œuvre ce:

1) Multi-héritage de table

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)
  # ...

Existe-il des problèmes avec l'utilisation de multi-héritage de table en conjonction avec l'utilisateur configurable modèle?

2) à l'Aide d'un modèle unique avec un attribut "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)
  # ...

Cette méthode nécessite un certain conditionnelle de validation dépend user_type.

Laquelle de ces méthodes correspond le mieux à mon cas d'utilisation? Ou peut-être il ya une meilleure façon d'atteindre cet objectif?

Aussi, Dans le cas numéro 1, comment puis-je filtre mes utilisateurs?

Merci.

29voto

borges Points 1565

Avertissement: Django 1.5 est très nouveau et les gens sont toujours en train d'enquêter sur ses nouvelles fonctionnalités. Donc, ma réponse est rien de plus que mon avis, basé sur des recherches récentes pour répondre à cette question.

Les deux moyens sont des moyens valables pour atteindre le résultat, avec ses avantages et ses inconvénients.

Commençons par l':

Deuxième option

  • Sans modèles imbriqués et non modulaires. AbstractBaseUser, comme son nom l'indique, est un modèle abstrait et ne pas avoir une table spécifique
  • A champs non utilisés
  • Vous devez vérifier la user_type pour toute itération avec le modèle qui utilise le champs supplémentaires:

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

Le SQL qui en résulte serait approximativement comme suit:

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
);

Première option

  • Modèles imbriqués avec la logique de séparation des entités
  • Très maigre
  • Vous devez implémenter BaseUserManager pour chaque enfant si vous souhaitez utiliser create_user-comme des fonctions
  • Vous ne pouvez pas accéder à la sous-classes avec un simple BaseUser.objects.all()*

Le SQL qui en résulte serait approximativement comme suit:

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
);

* Imaginez la situation suivante:

>>> 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>]

Donc, vous ne pouvez pas récupérer directement les sous-classes d'instances en utilisant BaseUser.objects.all(). Il y a un excellent post de blog par Jeff expliquer mieux comment accomplir automatique "triste" de l' BaseUser de son enfant.

Cela dit, vous devez considérer les avantages et les inconvénients de chaque approche et leur impact sur votre projet. Lorsque l'impliqués logique est petite (comme dans l'exemple décrit), les deux approches sont valables. Mais dans un scénario plus complexe, une approche peut être mieux que l'autre. Je choisirais le modèle multi option, car il est plus extensible.

6voto

Robert Points 41

Peut-être devriez-vous envisager AbstractUser?

2voto

maulik13 Points 1257

La nouvelle coutume de modèle d'utilisateur, vous pouvez affecter qu'un seul modèle de AUTH_USER_MODEL. Avec le multi-héritage de table, vous avez deux modèles. Ce qui est un problème.

Dans le cas d'un utilisateur unique modèle qui couvre tous les types d'utilisateur vous pourriez abstrait de la logique conditionnelle dans le modèle de méthodes. Vous pouvez également utiliser différents gestionnaires pour différents types d'utilisateurs basé sur combien ils sont différents. Cela pourrait aussi vous aider à être plus explicite lorsque l'on travaille avec un type d'utilisateur.

Autre option pourrait être de stocker uniquement la plupart des attributs communs dans un seul modèle d'utilisateur, puis attacher les spécificités des deux types d'utilisateurs dans leurs propres tableaux, qui sont liés à votre utilisateur principal de la table.

Si les deux utilisateurs ont le plus de choses en commun (en termes de données au moins), je tiens à les garder dans un endroit. En fin de compte, je pense à ce qui est plus simple et plus facile à maintenir.

1voto

Vladimir Prudnikov Points 2106

J'utiliserais un seul modèle avec un attribut "type". Voici pourquoi:

  • Une seule table, un seul modèle
  • Si vous voulez convertir d'un type à un autre, il vous suffit de modifier l'attribut
  • Implémentation des getters et des setters pour les champs qui existent pour un type et qui n’existent pas pour un autre = beaucoup plus simple à utiliser.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X