Подсчитайте и сгруппируйте по внешнему ключу и верните модель django - PullRequest
0 голосов
/ 17 ноября 2018

Модель данных:

  • Каждый 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

1 Ответ

0 голосов
/ 17 ноября 2018

Вам нужно изменить подход к набору запросов.Используйте Library вместо UserBookReceipt.

libraries = (Library.objects
    .filter(book__userbookreceipt__user=user)
    .annotate(rcount=Count('book__userbookreceipt', distinct=True))
    .order_by('-rcount')
)
[x.rcount for x in libraries]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...