Преобразование из базового экземпляра модели в производную модель прокси в Django? - PullRequest
9 голосов
/ 27 октября 2011

Я бы хотел определить прокси-модель для класса User по умолчанию в 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) 

на мой взгляд код.

Ответы [ 2 ]

4 голосов
/ 28 октября 2011

Если вы действительно хотите, чтобы полный прокси-объект был доступен, это быстрое и грязное решение (за счет дополнительного вызова базы данных)

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 }}
0 голосов
/ 03 августа 2018

Я думаю, что реальным ответом на этот вопрос должен быть комментарий @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

Краткий тест в оболочке:

>>> 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>
...