9
votes

Django: Pourquoi créer une Ometoone à UserProfile au lieu de la sous-classement Auth.User?

Remarque: Si vous êtes tenté de «répondre» à cette question en me disant que vous n'aimez pas django.contrib.auth, s'il vous plaît passez à autre chose. Ça ne sera pas utile. Je suis bien conscient de la gamme et de la force des opinions sur cette question.

Maintenant, la question:

La convention consiste à créer un modèle, UserProfile, avec un utilisateur à l'utilisateur.

À tous points de vue, une approche plus efficace et efficace consiste à une approche plus efficace et à la sous-classement à une classe que l'on entend utiliser pour chaque humain dans le système - une classe appelée, par exemple, personne (utilisateur).

Je n'ai pas vu une explication cohérente de la raison pour laquelle le premier est conventionnel et que ce dernier est considéré comme un hack. Il y a quelque temps, j'ai changé à l'approche de l'onetoone afin de pouvoir utiliser Get_Profile () et je l'ai regretté depuis. Je pense que vous pouvez passer à moins que je puisse être fait pour comprendre l'avantage de cette approche.


0 commentaires

3 Réponses :


4
votes

Vous vous rendez compte, n'est-ce pas que ce modèle sous-classement est mis en œuvre au moyen d'une relation oneoone sous la hotte? En fait, en ce qui concerne l'efficacité, je ne peux voir aucune différence entre ces deux méthodes.

Le sous-classement des modèles concrets existants est, à mon avis, un piratage méchant qui devrait être évité si possible. Il implique de cacher une relation de base de données afin qu'elle ne soit pas claire lorsque l'accès supplémentaire DB est effectué. Il est beaucoup plus clair de montrer les relations explicitement et d'y accéder explicitement si nécessaire.

Maintenant, une troisième alternative que je ressemble est de créer un modèle d'utilisateur totalement nouveau, ainsi qu'un backend d'authentification personnalisé qui renvoie des instances du nouveau modèle au lieu de la valeur par défaut. Créer un backend ne consiste à définir de quelques méthodes simples, il est donc très facile de le faire.


5 commentaires

Oui, bien sûr, je me rends compte que le sous-classement crée une "implicite" de l'onetoone. En termes de clarté et d'efficacité, personne.Email est beaucoup plus clair que UserProfile.user.Email. Pouvez-vous vous familiariser ce que le problème est avec le sous-classement des modèles existants? Votre troisième alternative m'a très intéressé. Y a-t-il un bon document que je peux lire sur cette technique?


De plus, sur votre deuxième paragraphe: Impossible de faire la même demande de la même demande de casse à la base de données de la base de données avec une base de données ordinaire sur un modèle concret? Ou dites-vous que depuis que vous n'avez pas TOUJOURS Besoin de la PK du parent, vous pouvez parfois sauver le voyage? Si tel est le cas, c'est un point assez juste, mais cela ne s'applique pas vraiment ici, car nous sommes toujours (au moins, dans tous les cas, je peux penser à) continuer à aller à l'utilisateur de toute façon.


Lorsque j'ai sous-classé l'utilisateur, cela a fonctionné pendant un moment, mais plus tard lorsque j'ai créé une relation de nombreusesTomanany "à travers", lorsque l'objet via Essayerait d'accéder au FK au module utilisateur sous-classé, il accéderait à la place au modèle d'utilisateur, ce qui a provoqué Toutes sortes de problèmes et n'étaient pas vraiment correctes sans entrer dans les internes de Django. C'était Django 1.3.1. J'ai changé pour simplement avoir des objets de profil qui pointent sur certains objets utilisateur et c'était résolu.


Ce post est-il obsolète? Je ne comprends pas pourquoi c'est un "noyer hack", d'autant plus que Django a maintenant le contrôle de la définition d'un modèle utilisateur personnalisé dans les paramètres et tout ce qui veut qu'un "utilisateur" puisse le récupérer avec get_user_model () (Je ne sais pas quand ce genre de choses a été ajouté cependant)


Le sous-classement A Béton Le modèle était et est toujours un piratage méchant. Sous-classement Un modèle abstrait, comme vous le faites lorsque vous sous-classes Absacutuser pour créer un modèle utilisateur personnalisé, c'est parfaitement bien, bien qu'il n'ait pas été disponible lorsque j'ai écrit ce poste.



0
votes

est-il plus efficace et efficace d'hériter du modèle utilisateur? Je ne vois pas pourquoi, mais j'aimerais lire vos arguments. Imnsho, le modèle héritier a toujours été une douleur.

Pourtant, cela peut ne pas répondre à votre question, mais je suis assez satisfait de la solution proposée par Will Hardy dans cet extrait . En tirant parti des signaux, il crée automatiquement un nouveau profil utilisateur pour chaque nouvel utilisateur. P>

Le lien est peu susceptible de disparaître, mais voici ma version légèrement différente de son code: P>

from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _

class AuthUserProfileModelBase(models.base.ModelBase):
    # _prepare is not part of the public API and may change
    def _prepare(self):
        super(AuthUserProfileModelBase, self)._prepare()
        def on_save(sender, instance, created, **kwargs):
            if created:
                self.objects.create(user=instance)
        # Automatically link profile when a new user is created
        post_save.connect(on_save, sender=User, weak=False)

# Every profile model must inherit this class
class AuthUserProfileModel(models.Model):
    class Meta:
        abstract = True
    __metaclass__ = AuthUserProfileModelBase
    user = models.OneToOneField(User, db_column='auth_user_id',
        primary_key=True, parent_link=True)

# The actual profile model
class Profile(AuthUserProfileModel):
    class Meta:
        app_label = 'some_app_label'
        db_table = 'auth_user_profile'
        managed = True
    language = models.CharField(_('language'), max_length=5, default='en')


10 commentaires

L'une des principales raisons pour lesquelles je considère l'héritage aussi favorable, du moins en théorie, est exprimée succinctement par la P.S. Dans l'extrait de Will de Will: "(PS: Il serait également agréable d'avoir le proxy de classe résultant que les attributs de l'objet utilisateur telles que le modèle de modèle de Django, tout en créant automatiquement un objet userProfile lors de la création d'un objet utilisateur :-)"


@Justin: Je ne le vois pas comme un véritable avantage surtout parce que le proxy est déjà une propriété - profil_instance.user.desired_attribute .


Welp, il y a des moments où je ne sais pas si j'ai un objet Africanswallow ou hirondelle, et je veux pouvoir accéder à ses noix de coco de toute façon. Cela me frappe un inconvénient de déterminer cela à l'avance - c'est tout l'héritage de la classe pour commencer.


(Et BTW, cette discussion aboutit carèrement dans une autre question de mienne, la réponse à laquelle vous obtiendra 50 points et beaucoup d'amour de moi :-). C'est ici: Stackoverflow.com/Questtions/5348157/... )


@Justin: Je ne vois pas de connexion. En fait, la question pointue semble assez éloignée de ce que nous discutons ici. Quand cette question se poserait-elle dans le scénario de votre question initiale? Désolé, mais je manque de réaliser.


Lorsque j'ai un objet parent et que je veux accéder à une méthode de l'objet enfant. Le statut de l'objet enfant en tant que membre d'une sous-classe est important car je souhaite peut-être accéder aux domaines (ou, à ce sujet), méthodes du parent.


@Justin: Je comprends cela, mais imo il n'a aucun lien avec votre question initiale. Et je crois que vous savez que parce que vous l'avez déjà comme une question différente. Vous ferez face à ce même problème de toute façon que vous résolvez cela, via héritage ou non. Je résoudrais que en ajoutant un Profile_Type propriété sur authtuserprofilemodel . De cette façon, toute requête crue peut également distinct entre eux. La difficulté ici est que Django vous permet seulement de configurer une classe de profil unique.


Pourquoi pas sec? AuthuserProfilemodel est une classe de base, de sorte que vous puissiez mettre les propriétés / méthodes partagées là-bas.


Dans le scénario, où est l'endroit faisant autorité où on cherche à comprendre quel type de profil est-il? Il y a deux places: 1) les connaissances inhérentes à l'objet de type OB IT, et 2) dans Profile_Type.


Je suis d'accord avec ce point. Bien que la réponse à votre autre question soit résolue cela. En attendant, nous devons accepter la façon dont Python fonctionne, ou trouvez cette réponse nous-mêmes.



2
votes

Il n'y a jamais vraiment été une bonne explication, du moins des sources "officielles" quant à la raison pour laquelle, dans la pratique, l'utilisateur de sous-classement est moins utile que d'avoir un ussurofile.

Cependant, j'ai quelques raisons, qui sont venues après avoir décidé que l'utilisateur de sous-classement était "la voie à suivre".

  • Vous avez besoin d'un backend d'authentification personnalisé. Ce n'est pas un gros problème, mais moins vous devez écrire du code, meilleur.
  • D'autres applications peuvent supposer que votre utilisateur est un django.contrib.auth.models.user . Pour la plupart, cela ira bien, à moins que ce code ne récupère à des objets utilisateur. Parce que nous sommes une sous-classe, tout code utilisant simplement nos objets utilisateur devrait être bien.
  • Un utilisateur peut seulement "être" une sous-classe à la fois. Par exemple, si vous aviez des sous-classes utilisateur de l'étudiant et de l'enseignant, alors à un moment donné, votre utilisateur ne pourra être qu'un enseignant ou un étudiant. Avec UserProfiles, il pourrait y avoir à la fois un enseignant et un profil d'étudiant au même moment.
  • Suite, la conversion d'une sous-classe à une autre est dure: surtout si vous avez déjà une instance d'une sous-classe déjà.

    Donc, vous pouvez dire que "mon projet ne disposera que de la sous-classe d'un utilisateur". C'est ce que je pensais. Nous avons maintenant trois utilisateurs réguliers et éventuellement un quatrième. Les exigences changent , devoir modifier les tas de code pour traiter ce qui n'est pas très amusant.

    Note: Il y a eu beaucoup de discussions sur Django-développeurs récemment sur une meilleure solution aux problèmes liés au modèle d'utilisateur Contrib.Auth.


1 commentaires

Si des autres applications supposent django.contrib.auth.models.user , ils doivent être réécrites d'utiliser get_user_model ()