从基本模型实例转换为Django中的派生代理模型?

sla*_*acy 9 python django django-models

我想为Django的默认User类定义一个代理模型,有点像这样:

class MyUser(User):

    def pretty_username(self): 
        if self.first_name:
            return self.first_name
        return self.username 

    class Meta: 
        proxy = True 
Run Code Online (Sandbox Code Playgroud)

而且,我希望能够从视图代码中调用pretty_username(理想情况下,甚至可以从模板中调用).是否有一种简单的方法来获取标准用户模型的实例并将其类型转换为MyUser的实例?

__init__只要我可以说,即使是一些魔法对我也没关系

my_user = MyUser(request.user) 
Run Code Online (Sandbox Code Playgroud)

在我的视图代码中.

Joh*_*ang 5

我认为这个问题的实际答案应该是@fhahn 在另一个答案中的评论。通过更改类,我们可以避免额外的数据库调用。这是示例代码:

我的代理模型将表示从 更改usernameemail如果设置:

class MyUser(User):
    class Meta:
        proxy = True
        verbose_name = _('my user')
        verbose_name_plural = _('my users')

    def __str__(self):
        return "%s" % (self.email or self.username)

class Wallet(models.Model):
    owner = models.OneToOneField(MyUser, on_delete=models.PROTECT, related_name='wallet')

    def __str__(self):
        return "%s" % self.owner
Run Code Online (Sandbox Code Playgroud)

在 shell 中进行一个简短的测试:

>>> from django.contrib.auth.models import User
>>> from my_apps.models import MyUser
>>> user = User.objects.get(pk=4)
>>> user
<User: AbKec6rumI9H9UmAC3Bh2kXUHzj4>
>>> user.email
'john@example.com'
>>> user.wallet
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'User' object has no attribute 'wallet'
>>> user.__class__ = MyUser
>>> user
<MyUser: john@example.com>
>>> user.wallet
<Wallet: john@example.com>
Run Code Online (Sandbox Code Playgroud)


Eva*_*ley 4

如果您确实想让完整的代理对象可用,这是一个快速而肮脏的解决方案(以额外的数据库调用为代价)

class MyUser(User):

    def pretty_username(self): 
        if self.first_name:
            return self.first_name
        return self.username 

    class Meta: 
        proxy = True


def get_myuser(self):
    try:
        return MyUser.objects.get(pk=self.pk)
    except MyUser.DoesNotExist:
        return None

User.add_to_class('get_myuser', get_myuser)
Run Code Online (Sandbox Code Playgroud)

因此,要在视图中使用它,您可以说:

request.user.get_myuser().pretty_username()
Run Code Online (Sandbox Code Playgroud)

或者在模板中:

{{ request.user.get_myuser.pretty_username }}
Run Code Online (Sandbox Code Playgroud)

如果您不依赖代理模型的想法,更好的解决方案如下:

def pretty_username(self):
    if self.first_name:
        return self.first_name
    return self.username

User.add_to_class('pretty_username', pretty_username)
Run Code Online (Sandbox Code Playgroud)

这将允许以下操作:

request.user.pretty_username()
Run Code Online (Sandbox Code Playgroud)

或者

{{ request.user.pretty_username }}
Run Code Online (Sandbox Code Playgroud)

  • get_myuser 方法必须将用户对象的类型从 User 更改为 MyUser。这可以使用“__class__”属性来完成:“def get_myuser(self): self.__class__ = MyUser”,无需额外的数据库调用 (15认同)