Как правильно сделать этот сложный Django queryset?
Допустим, у меня есть эти три модели:
class Author(models.Model):
name = models.CharField(max_length=64)
class Book(models.Model):
author = models.ForeignKey(
Author,
blank=True,
null=True,
on_delete=models.SET_NULL
)
name = models.CharField(max_length=64)
class Store(models.Model):
books = models.ManyToManyField(Book)
name = models.CharField(max_length=64)
Я не знаю автора некоторых книг. В этих случаях автор равен нулю.
При запросе Store я хотел бы узнать, сколько книг есть в каждом магазине, и отсортировать их. Поэтому мой набор запросов выглядит примерно так:
Store.objects.all().annotate(books_count=Count('books')).order_by('-books_count')
Теперь, что если я хочу подсчитать только те книги, у которых есть автор?
Я попробовал этот набор вопросов, но он явно не корректен:
filter = Q(books__author__isnull=False)
Store.objects.annotate(books_count=Count(filter)).all().order_by('-books_count')
Кто-нибудь знает правильный способ выполнения этого запроса?
Вы можете пойти другим путем:
Book.objects.filter(author__isnull=False).values('store_set').annotate(count=Count('store_set')).order_by('-count')
Я сделаю небольшое предположение, но я думаю, что ваше использование объекта Q
может быть неправильным внутри объекта Count
.
Count
ожидается выражение типа объект, это может быть строка, F, OuterRef, SubQuery и так далее.
Store.objects.filter(filter).annotate(
books_count=Count("books")
).order_by('-books_count')
Думаю, это то, что вам нужно.
Я считаю, что следующий запрос - это то, что вы ищете.
books_count = (
Book.objects.filter(
store=OuterRef('pk'),
author__isnull=False,
)
.annotate(count=Func(F("id"), function="COUNT"))
.values("count")
)
Store.objects.annotate(count=Subquery(books_count)).order_by('-count')