Модель данных:
- Каждый
Library
имеет много Book
с
- Каждый
Book
может или не может быть прочитан User
, продиктованным UserBookReceipt
Цель:
Для пользователя упорядочьте библиотеки по количеству книг, которые они прочитали в каждой библиотеке.
Пример:
Пользователь 1 прочитал:
- 2 книги из библиотеки 1
- 5 книг из библиотеки 2
- 1 книга из библиотеки 3
- 0 книг из библиотеки 4
Мы должны возвращать библиотеки в порядке количества книг, прочитанных пользователем 1, т.е.:
Library 2, Library 1, Library 3
Текущее решение
libraries = (UserBookReceipt.objects
.filter(user=user)
.values('book__library')
.annotate(rcount=Count('book__library'))
.order_by('-rcount')
)
Фактическая выработка
[
{'book_library': 2, 'rcount': 5},
{'book_library': 1, 'rcount': 2},
{'book_library': 3, 'rcount': 1}
]
Ожидаемый результат
[
{'book_library': <Library: 2>, 'rcount': 5},
{'book_library': <Library: 1>, 'rcount': 2},
{'book_library': <Library: 3>, 'rcount': 1}
]
Фактический вывод составляет 90% от того, что я хочу, за исключением того, что я хочу, чтобы значение book_library
было экземплярами модели django Library
, а не просто идентификатором библиотеки. В противном случае мне придется сделать еще один запрос для извлечения объектов Library
, что, вероятно, потребует некоторого неэффективного ids__in
запроса .
Как подсчитать и сгруппировать по UserBookReceipt.book__library
и вернуть модель библиотеки?
Если бы я делал это в SQL, запрос был бы похож на
with rcount_per_lib as (
select lib.id, count(*) as rcount
from lib, books, user_book_receipts
where user_book_receipts.book_id = books.id
and lib.id = books.lib_id
and user_book_receipts.user_id = 1
group by lib.id)
select lib.*, rcount from rcount_per_lib
where lib.id = rcount_per_lib.id
order by rcount