我想为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)
在我的视图代码中。
答案 0 :(得分: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)
所以要在视图中使用它,你可以说:
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 }}
答案 1 :(得分:0)
我认为这个问题的实际答案应该是@fhahn在另一个答案中的评论。通过更改 class ,我们可以避免额外的数据库调用。这是示例代码:
我的代理模型,如果设置的话,其表示形式将从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
'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>