Как я могу аннотировать? - PullRequest
3 голосов
/ 30 октября 2019

Как можно аннотировать все копии_проданных книг для каждого 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

1 Ответ

1 голос
/ 30 октября 2019

Это не Count, а Sum:

from django.db.models import <b>Sum</b>

class AuthorQuerySet(models.QuerySet):

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

Каждый Book содержит целое число, которое содержит количество проданных копий, поэтому для получения общего количества,Вы суммируете эти числа для всех книг, написанных этим автором.

Для Author s без связанных Book s (которые удовлетворяют фильтру), мы можем использовать Coalesce выражение [Джанго-док] :

from django.db.models import Sum, <b>V</b>
from django.db.models.functions import <b>Coalesce</b>

class AuthorQuerySet(models.QuerySet):

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