首页 > 解决方案 > 我该如何注释?

问题描述

我如何为每本书注释所有已售出的书籍Author

from django.db import models
from django.db.models import Count


class AuthorQuerySet(models.QuerySet):
    def annotate_with_copies_sold(self):
        return Author.objects.annotate(num_copies=Count('books__copies_sold'))


class AuthorManager(models.Manager):
    def get_queryset(self):
        return AuthorQuerySet(self.model, using=self._db)

    def annotate_with_copies_sold(self):
        return self.get_queryset().annotate_with_copies_sold()


class Author(models.Model):
    objects = AuthorManager()
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)


class Book(models.Model):
    title = models.CharField(max_length=30)
    copies_sold = models.PositiveIntegerField()
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')

断言失败

Output (stderr):
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
    yield
  File "/usr/local/lib/python3.6/unittest/case.py", line 605, in run
    testMethod()
  File "/task/assignment/tests.py", line 92, in test_annotating_works_with_filtering
    "Annotating with copies sold should work well with filtering")
  File "/usr/local/lib/python3.6/unittest/case.py", line 829, in assertEqual
    assertion_func(first, second, msg=msg)
  File "/usr/local/lib/python3.6/unittest/case.py", line 822, in _baseAssertEqual
    raise self.failureException(msg)
AssertionError: 3 != 2 : Annotating with copies sold should work well with filtering


Output (stderr):
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
    yield
  File "/usr/local/lib/python3.6/unittest/case.py", line 605, in run
    testMethod()
  File "/task/assignment/tests.py", line 29, in test_should_annotate
    self.assertIsNotNone(Author.objects.annotate_with_copies_sold().first().copies_sold,
AttributeError: 'Author' object has no attribute 'copies_sold'
RUNTIME ERROR

标签: djangodjango-models

解决方案


这不是一个Count,而是一个Sum

from django.db.models import Sum

class AuthorQuerySet(models.QuerySet):

    def annotate_with_copies_sold(self):
        return Author.objects.annotate(num_copies=Sum('books__copies_sold'))

每个都Book包含一个整数,其中包含已售出的副本数量,因此为了检索总数,您可以将这些数字与该作者所写的所有书籍相加。

对于Author没有相关Books 的 s(满足过滤器),我们可以使用Coalesce表达式 [Django-doc]

from django.db.models import Sum, V
from django.db.models.functions import Coalesce

class AuthorQuerySet(models.QuerySet):

    def annotate_with_copies_sold(self):
        return Author.objects.annotate(num_copies=Coalesce(Sum('books__copies_sold'), V(0)))

推荐阅读