按外键计数和分组并返回模型django

时间:2018-11-17 14:29:26

标签: python sql django postgresql

数据模型:

  • 每个Library有许多Book
  • Book规定的User可能会或可能不会读取每个UserBookReceipt

目标:

给出一个用户,按照他们在每个图书馆看过多少书来对图书馆进行排序。

示例:

用户1已阅读:

  • 2本图书馆1本书
  • 5本图书馆2本书
  • 图书馆3中的1本书
  • 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模型的实例,而不仅仅是库ID。否则,我必须进行另一个查询来检索Library对象,这可能需要一些效率低下的ids__in query

如何计算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 :(得分:2)

您需要更改处理查询集的方式。使用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]