Как добавить пользовательские атрибуты в QuerySets в Django? - PullRequest
1 голос
/ 03 октября 2019

рассмотрим следующие модели:

class User(AbstractUser):
    def messages(self):
        return Message.objects.filter(user=self).order_by('-created_on')

class Message(models.Model):
    user = models.ForeignKey('account.User', related_name='message', on_delete=models.CASCADE)
    created_on = models.DateTimeField(auto_now=True)
    data = models.TextField()
    read = models.BooleanField(default=False)

    objects = MessageManager()

Я хочу переопределить поведение QuerySet для модели Message, чтобы включить пользовательский метод, unread_count:

class MessageManager(models.Manager):
    def get_queryset(self):
        queryset = super().get_queryset()
        unread_count = queryset.filter(read=False).count()
        print(unread_count) # this works

        # these don't work
        queryset.unread_count = unread_count
        setattr(queryset, 'unread_count', unread_count)
        #

        return queryset

messages метод работает нормально, и оператор print внутри менеджера выполняется, но если я пытаюсь получить доступ к unread_count, я получаю AttributeError:

>>>user = User.objects.get(id=1)
>>>messages = user.messages()
2 # this is from the print statement
>>>messages.unread_count
AttributeError: 'QuerySet' object has no attribute 'unread_count'

Что мне здесь не хватает?

1 Ответ

0 голосов
/ 03 октября 2019

Вместо models.Manager, вы должны подклассифицировать models.QuerySet:

class MessageQuerySet(models.QuerySet):
    @property
    def unread_count(self):
        return self.filter(read=False).count()

Затем используйте метод as_manager в вашей модели:

class Message(models.Model):
    ...

    objects = MessageQuerySet.as_manager()

Если вам нужно добавить методы как к QuerySet, возвращенному от менеджера, так и к самому менеджеру, вам нужно будет использовать from_queryset:

class MessageManager(models.Manager):
    def some_manager_only_method(self):
        print('do stuff')

class MessageQuerySet(models.QuerySet):
    @property
    def unread_count(self):
        return self.filter(read=False).count()

class Message(models.Model):
    ...

    objects = MessageManager.from_queryset(MessageQuerySet)()
...