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

发布于 2024-12-12 01:15:39 字数 484 浏览 0 评论 0原文

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

class MyUser(User):

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

    class Meta: 
        proxy = True 

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

即使是一些 __init__ 魔法对我来说也没什么问题,只要我能说:

my_user = MyUser(request.user) 

在我的视图代码中。

I'd like to define a proxy Model for Django's default User class, something kind of like this:

class MyUser(User):

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

    class Meta: 
        proxy = True 

And, I'd like to be able to call pretty_username from view code (and ideally, even from templates). Is there a simple way to take an instance of a standard User Model and type-cast it into an instance of MyUser?

Even some __init__ magic would be okay with me, as long as I can say:

my_user = MyUser(request.user) 

in my view code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

遮云壑 2024-12-19 01:15:39

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

我的代理模型,如果设置,则将表示形式从 username 更改为 email

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

在 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
'[email protected]'
>>> 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: [email protected]>
>>> user.wallet
<Wallet: [email protected]>

I think the actual answer to this question should be the comment by @fhahn in the other answer. And by changing class we can avoid the extra database call. Here is sample code:

My proxy model which change the representation from username to email if set:

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

A brief test in 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
'[email protected]'
>>> 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: [email protected]>
>>> user.wallet
<Wallet: [email protected]>
三生殊途 2024-12-19 01:15:39

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

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)

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

request.user.get_myuser().pretty_username()

或者在模板中:

{{ request.user.get_myuser.pretty_username }}

一个更好的解决方案,如果您不受代理模型想法的束缚,将是以下内容:

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

User.add_to_class('pretty_username', pretty_username)

这将允许以下内容:

request.user.pretty_username()

或者

{{ request.user.pretty_username }}

If you really want to have the full proxy object available, this is a quick and dirty solution (at the expense of an extra database call)

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)

So to use this in a view you could say:

request.user.get_myuser().pretty_username()

Or in a template:

{{ request.user.get_myuser.pretty_username }}

A nicer solution, if you're not tied to the proxy model idea, would be the following:

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

User.add_to_class('pretty_username', pretty_username)

This would allow the following:

request.user.pretty_username()

Or

{{ request.user.pretty_username }}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文