这是简化的问题,我有一个Book模型:
class Book(models.Model):
language = models.CharField(max_length=2, choices=LANGUAGE_CHOICES)
...
我使用django-hitcount来计算我的图书的视图(可能没有人知道它,因为它是一个旧项目),无论如何让我粗略总结一下:它创建一个HitCount对象,其中包含一个命中计数器和一个GenericForeignKey到各自的对象。
我想获得一本特定语言的15本书,点击率更高,显然是按点击顺序排列。
我已经查看了this question,它帮助我找出了我的(部分)解决方案,分为3个查询:
翻译成代码:
content_type = ContentType.objects.get_for_model(Book)
books = tuple(Books.objects.filter(
language=language).values_list('id', flat=True))
all_time = list(HitCount.objects.filter(
content_type=content_type,
object_pk__in=books).values_list(
'object_pk', 'hits').order_by('-hits')[:15])
all_time_ids = [i[0] for i in all_time]
best_of_all_time = Books.objects.select_related(
'manga').filter(pk__in=all_time_ids)
这种方法存在两个问题:
有人有建议吗?
答案 0 :(得分:1)
而不是id列表将查询集传递给object_pk__in
条件。 Django非常聪明,可以将其转换为SQL子查询,因此所有费用都将由SQL服务器处理,这也很聪明: - )
使用queryset的in_bulk()
方法获取一个易于访问的图书词典。
所以代码看起来像这样:
# just queryset instead of tuple of ids
books = Books.objects.filter(language=language).values_list('id', flat=True)
rating = list(HitCount.objects.filter(content_type=content_type,
object_pk__in=books)
.values_list('object_pk', 'hits')
.order_by('-hits')[:15])
book_ids = [r[0] for r in rating]
# dict of Books with book.pk as a key
books_d = Books.objects.select_related('manga').in_bulk(book_ids)
# list of tuples (book, hits) ordered by -hits
best_of_all_time = [books_d[pk], hits for pk, hits in rating]