#python #django #django-models
#python #django #django-модели
Вопрос:
Я хотел бы определить прокси-модель для пользовательского класса Django по умолчанию, что-то вроде этого:
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)
на мой взгляд, код.
Комментарии:
1. Похоже, вы пытаетесь создать оболочку или адаптер для пользовательского класса. Было бы что-то вроде этого: ginstrom.com/scribbles/2009/03/27/the-adapter-pattern-in-python сделать трюк?
Ответ №1:
Я думаю, что фактическим ответом на этот вопрос должен быть комментарий @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
Краткий тест в оболочке:
>>> 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>
Ответ №2:
Если вы действительно хотите, чтобы был доступен полный прокси-объект, это быстрое и грязное решение (за счет дополнительного вызова базы данных)
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. Метод get_myuser должен изменить тип объекта user с User на MyUser. Это можно сделать с помощью
__class__
атрибута:def get_myuser(self): self.__class__ = MyUser
без дополнительного вызова базы данных