自定义用户类在django中断应用程序?

时间:2021-05-31 19:23:42

Let's say that I have subclassed User model (CustomUser) properly (as explained here: http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/)

假设我已经正确地将用户模型(CustomUser)子类化了(如下所述:http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/)

and installed the comments app.

并安装了评论应用。

to access the user of a comment in the template I write:

访问我写的模板中的注释用户:

{{comment.user}} # which provides User, not my CustomUser

and therefore,

{{comment.user.CustomProperty}} #does not work.

How can I work around it?

我该如何解决这个问题?

3 个解决方案

#1


The ForeignKey from comments.Comment is to django's built-in User object, so querying comment.user will give you the parent object (ie: the base User model). However, django inheritance does provide a way to get the subclass version from the superclass:

来自comments.Conment的ForeignKey是django的内置User对象,因此查询comment.user将为您提供父对象(即:基本用户模型)。但是,django继承确实提供了从超类获取子类版本的方法:

{{ comment.user.customeruser }}

Which would then allow you to do:

那将允许你这样做:

{{ comment.user.customeruser.customproperty }}

I happen to think this is a weakness in Django's inheritance implementation since it doesn't exactly mirror the behaviour you'd expect from object inheritance in Python generally, but at least there is a workaround. Since I'm hardly rushing out to submit a patch with my version of the right behaviour, I can't complain :-)

我碰巧认为这是Django的继承实现中的一个弱点,因为它并不能完全反映Python中对象继承所期望的行为,但至少有一种解决方法。由于我很难急于提交我的正确行为版本的补丁,我不能抱怨:-)


I agree with Carl Meyer's comment: it could expensive to automatically fetch the subclass without altering the parent model's db table, and returning the instance of the subclass from the parent class query would be inconsistent with Django's promise that a queryset returns the model on which the queryset was run.

我同意Carl Meyer的评论:在不改变父模型的db表的情况下自动获取子类可能很昂贵,并且从父类查询返回子类的实例将与Django的承诺不一致,即查询集返回模型,其中queryset已运行。

I still find in practice, however, that Django's inheritance leads to some awkward extra steps on occasion. Having used Django since 0.91, and knowing that all the different strategies for resolving object-relational mapping issues have tradeoffs, I'm very happy to have inheritance in Django now, and feel that the current implementation is excellent... so I'd hate for my original answer to be construed as a slight against the project.

然而,我仍然在实践中发现,Django的继承有时会导致一些尴尬的额外步骤。从0.91开始使用Django,并且知道解决对象关系映射问题的所有不同策略都有权衡,我很高兴现在在Django中继承,并且觉得当前的实现非常好......所以我想讨厌我的原始答案被解释为对项目的轻微反对。

As such, I thought I would edit this answer to link to an answer Carl himself provided on a solution in cases where you don't know what type the subclass is: How do I access the child classes of an object in Django without knowing the name of the child class?. He offers advice there for using the ContentType framework. Still some indirection involved, but a good, generalizable, option in the toolkit.

因此,我想我会编辑这个答案,链接到Carl自己在解决方案中提供的答案,如果您不知道子类是什么类型的话:如何在不知道的情况下访问Django中对象的子类子类的名称?他在那里提供了使用ContentType框架的建议。还有一些间接涉及,但工具包中有一个很好的,可推广的选项。

#2


As you can see in the comments of that post, it is still controversially discussed, what is the best way.

正如你在该帖子的评论中所看到的那样,它仍然存在争议性的讨论,最好的方法是什么。

I tried it by subclassing too, but I ran in many problems, while using profiles work perfectly for me.

我通过子类化尝试了它,但是我遇到了很多问题,而使用配置文件对我来说非常合适。

class IRCUser(models.Model):
    user        = models.ForeignKey(User, unique=True)
    name        = models.CharField(max_length=100, blank= True, null = True )
    friends     = models.ManyToManyField("IRCUser", blank= True, null = True)
    dataRecieved= models.BooleanField(default=False)

creating an IRCUser works like this:

创建一个IRCUser的工作方式如下:

>>> IRCUser(user = User.objects.get(username='Kermit')).save()

EDIT: Why are user_profiles elegant:

编辑:为什么user_profiles优雅:

Let's assume, we are writing a webapp, that will behave as a multi-protocol chat. The users can provide their accounts on ICQ, MSN, Jabber, FaceBook, Google Talk .....

让我们假设,我们正在编写一个webapp,它将表现为多协议聊天。用户可以在ICQ,MSN,Jabber,FaceBook,Google Talk上提供账户.....

We are free to create a custom user class by inheritance, that will hold all the additional informations.

我们可以通过继承*创建自定义用户类,它将保存所有其他信息。

class CustomUser(User):
    irc_username = models.CharField(blank=True, null=True)
    irc_password = models.PasswordField(blank=True, null=True)
    msn_username = models.CharField(blank=True, null=True)
    msn_password = models.PasswordField(blank=True, null=True)
    fb_username = models.CharField(blank=True, null=True)
    fb_password = models.PasswordField(blank=True, null=True)
    gt_username = models.CharField(blank=True, null=True)
    gt_password = models.PasswordField(blank=True, null=True)
    ....
    ....

this leads to

这导致

  • data-rows with a lot of zero-values
  • 具有大量零值的数据行

  • tricky what-if-then validation
  • 棘手的假设然后验证

  • the impossibility, to have more the one account with the same service
  • 不可能,拥有更多同一服务的帐户

So now let's do it with user_profiles

所以现在让我们用user_profiles来做

class IRCProfile(models.Model):
    user = models.ForeignKey(User, unique=True, related_name='ircprofile')
    username = models.CharField()
    password = models.PasswordField()

class MSNProfile(models.Model):
    user = models.ForeignKey(User, unique=True, related_name='msnprofile')
    username = models.CharField()
    password = models.PasswordField()

class FBProfile(models.Model):
    user = models.ForeignKey(User, unique=True, related_name='fbprofile')
    username = models.CharField()
    password = models.PasswordField()

the result:

  • User_profiles can be created when needed
  • 可以在需要时创建User_profiles

  • the db isn't flooded by zero-values
  • 数据库不会被零值淹没

  • n profiles of same type can be assigned to one user
  • n个相同类型的配置文件可以分配给一个用户

  • validation is easy
  • 验证很容易

this may lead to a more cryptic syntax in the templates, but we are free to have some shortcuts in our views/template_tags or to use {% with ... %} to flavour it as we want.

这可能会导致模板中的语法更加神秘,但我们可以在views / template_tags中*选择一些快捷方式,或者使用{%with ...%}来调整它们。

#3


I don’t think there is a way around it, because as you said, comment.user is a User, not a CustomUser.

我认为没有办法绕过它,因为正如你所说,comment.user是用户,而不是CustomUser。

See http://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models:

QUERYSETS STILL RETURN THE MODEL THAT WAS REQUESTED
There is no way to have Django return, say, a MyUser object whenever you query for User objects. A queryset for User objects will return those types of objects. The whole point of proxy objects is that code relying on the original User will use those and your own code can use the extensions you included (that no other code is relying on anyway). It is not a way to replace the User (or any other) model everywhere with something of your own creation.

QUERYSET仍然返回要求的模型无论何时查询User对象,都无法让Django返回MyUser对象。 User对象的查询集将返回这些类型的对象。代理对象的重点是依赖于原始用户的代码将使用这些代码,并且您自己的代码可以使用您包含的扩展(无论如何其他代码都不依赖)。它不是用你自己创造的东西替换用户(或任何其他)模型的方法。

Maybe in this case, the old way of using UserProfile would be a better choice?

也许在这种情况下,使用UserProfile的旧方法会是更好的选择吗?

Sorry if I’m not helping much.

对不起,如果我没有多少帮助。

#1


The ForeignKey from comments.Comment is to django's built-in User object, so querying comment.user will give you the parent object (ie: the base User model). However, django inheritance does provide a way to get the subclass version from the superclass:

来自comments.Conment的ForeignKey是django的内置User对象,因此查询comment.user将为您提供父对象(即:基本用户模型)。但是,django继承确实提供了从超类获取子类版本的方法:

{{ comment.user.customeruser }}

Which would then allow you to do:

那将允许你这样做:

{{ comment.user.customeruser.customproperty }}

I happen to think this is a weakness in Django's inheritance implementation since it doesn't exactly mirror the behaviour you'd expect from object inheritance in Python generally, but at least there is a workaround. Since I'm hardly rushing out to submit a patch with my version of the right behaviour, I can't complain :-)

我碰巧认为这是Django的继承实现中的一个弱点,因为它并不能完全反映Python中对象继承所期望的行为,但至少有一种解决方法。由于我很难急于提交我的正确行为版本的补丁,我不能抱怨:-)


I agree with Carl Meyer's comment: it could expensive to automatically fetch the subclass without altering the parent model's db table, and returning the instance of the subclass from the parent class query would be inconsistent with Django's promise that a queryset returns the model on which the queryset was run.

我同意Carl Meyer的评论:在不改变父模型的db表的情况下自动获取子类可能很昂贵,并且从父类查询返回子类的实例将与Django的承诺不一致,即查询集返回模型,其中queryset已运行。

I still find in practice, however, that Django's inheritance leads to some awkward extra steps on occasion. Having used Django since 0.91, and knowing that all the different strategies for resolving object-relational mapping issues have tradeoffs, I'm very happy to have inheritance in Django now, and feel that the current implementation is excellent... so I'd hate for my original answer to be construed as a slight against the project.

然而,我仍然在实践中发现,Django的继承有时会导致一些尴尬的额外步骤。从0.91开始使用Django,并且知道解决对象关系映射问题的所有不同策略都有权衡,我很高兴现在在Django中继承,并且觉得当前的实现非常好......所以我想讨厌我的原始答案被解释为对项目的轻微反对。

As such, I thought I would edit this answer to link to an answer Carl himself provided on a solution in cases where you don't know what type the subclass is: How do I access the child classes of an object in Django without knowing the name of the child class?. He offers advice there for using the ContentType framework. Still some indirection involved, but a good, generalizable, option in the toolkit.

因此,我想我会编辑这个答案,链接到Carl自己在解决方案中提供的答案,如果您不知道子类是什么类型的话:如何在不知道的情况下访问Django中对象的子类子类的名称?他在那里提供了使用ContentType框架的建议。还有一些间接涉及,但工具包中有一个很好的,可推广的选项。

#2


As you can see in the comments of that post, it is still controversially discussed, what is the best way.

正如你在该帖子的评论中所看到的那样,它仍然存在争议性的讨论,最好的方法是什么。

I tried it by subclassing too, but I ran in many problems, while using profiles work perfectly for me.

我通过子类化尝试了它,但是我遇到了很多问题,而使用配置文件对我来说非常合适。

class IRCUser(models.Model):
    user        = models.ForeignKey(User, unique=True)
    name        = models.CharField(max_length=100, blank= True, null = True )
    friends     = models.ManyToManyField("IRCUser", blank= True, null = True)
    dataRecieved= models.BooleanField(default=False)

creating an IRCUser works like this:

创建一个IRCUser的工作方式如下:

>>> IRCUser(user = User.objects.get(username='Kermit')).save()

EDIT: Why are user_profiles elegant:

编辑:为什么user_profiles优雅:

Let's assume, we are writing a webapp, that will behave as a multi-protocol chat. The users can provide their accounts on ICQ, MSN, Jabber, FaceBook, Google Talk .....

让我们假设,我们正在编写一个webapp,它将表现为多协议聊天。用户可以在ICQ,MSN,Jabber,FaceBook,Google Talk上提供账户.....

We are free to create a custom user class by inheritance, that will hold all the additional informations.

我们可以通过继承*创建自定义用户类,它将保存所有其他信息。

class CustomUser(User):
    irc_username = models.CharField(blank=True, null=True)
    irc_password = models.PasswordField(blank=True, null=True)
    msn_username = models.CharField(blank=True, null=True)
    msn_password = models.PasswordField(blank=True, null=True)
    fb_username = models.CharField(blank=True, null=True)
    fb_password = models.PasswordField(blank=True, null=True)
    gt_username = models.CharField(blank=True, null=True)
    gt_password = models.PasswordField(blank=True, null=True)
    ....
    ....

this leads to

这导致

  • data-rows with a lot of zero-values
  • 具有大量零值的数据行

  • tricky what-if-then validation
  • 棘手的假设然后验证

  • the impossibility, to have more the one account with the same service
  • 不可能,拥有更多同一服务的帐户

So now let's do it with user_profiles

所以现在让我们用user_profiles来做

class IRCProfile(models.Model):
    user = models.ForeignKey(User, unique=True, related_name='ircprofile')
    username = models.CharField()
    password = models.PasswordField()

class MSNProfile(models.Model):
    user = models.ForeignKey(User, unique=True, related_name='msnprofile')
    username = models.CharField()
    password = models.PasswordField()

class FBProfile(models.Model):
    user = models.ForeignKey(User, unique=True, related_name='fbprofile')
    username = models.CharField()
    password = models.PasswordField()

the result:

  • User_profiles can be created when needed
  • 可以在需要时创建User_profiles

  • the db isn't flooded by zero-values
  • 数据库不会被零值淹没

  • n profiles of same type can be assigned to one user
  • n个相同类型的配置文件可以分配给一个用户

  • validation is easy
  • 验证很容易

this may lead to a more cryptic syntax in the templates, but we are free to have some shortcuts in our views/template_tags or to use {% with ... %} to flavour it as we want.

这可能会导致模板中的语法更加神秘,但我们可以在views / template_tags中*选择一些快捷方式,或者使用{%with ...%}来调整它们。

#3


I don’t think there is a way around it, because as you said, comment.user is a User, not a CustomUser.

我认为没有办法绕过它,因为正如你所说,comment.user是用户,而不是CustomUser。

See http://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models:

QUERYSETS STILL RETURN THE MODEL THAT WAS REQUESTED
There is no way to have Django return, say, a MyUser object whenever you query for User objects. A queryset for User objects will return those types of objects. The whole point of proxy objects is that code relying on the original User will use those and your own code can use the extensions you included (that no other code is relying on anyway). It is not a way to replace the User (or any other) model everywhere with something of your own creation.

QUERYSET仍然返回要求的模型无论何时查询User对象,都无法让Django返回MyUser对象。 User对象的查询集将返回这些类型的对象。代理对象的重点是依赖于原始用户的代码将使用这些代码,并且您自己的代码可以使用您包含的扩展(无论如何其他代码都不依赖)。它不是用你自己创造的东西替换用户(或任何其他)模型的方法。

Maybe in this case, the old way of using UserProfile would be a better choice?

也许在这种情况下,使用UserProfile的旧方法会是更好的选择吗?

Sorry if I’m not helping much.

对不起,如果我没有多少帮助。