我有对象Reports和ReportSubscriber,我想计算报告的订阅者数量。
一种解决方案是注释。我有很多报告所以注释所有这些都需要大约6秒钟,所以我想也许最好在分页后进行注释:
filter_search = ReportFilter(request.GET, queryset=Report.objects.filter(
created_at__gt=start_date,
created_at__lte=end_date,
is_confirmed__exact=True,
).annotate(sub_count=Count("reportsubscriber")).order_by('-sub_count'))
paginator = Paginator(filter_search, 20)
result = paginator.page(1).object_list.annotate(
sub_count=Count("reportsubscriber"))
它有效,但是花了相同的时间,当我检查查询时,它实际上仍然遍历report_subscriber表中的所有行。所以我尝试使用.extra()
filter_search = ReportFilter(request.GET, queryset=Report.objects.filter(
created_at__gt=start_date,
created_at__lte=end_date,
is_confirmed__exact=True,
))
paginator = Paginator(filter_search, 20)
paged_reports = paginator.page(1)
result = filter_search.qs.extra(
select={
'sub_count': 'SELECT COUNT(*) FROM reports LEFT OUTER JOIN report_subscribers \
ON (reports.id = report_subscribers.id) \
WHERE reports.id = report_subscribers.id \
AND report_subscribers.report_id IN %s \
' % "(%s)" % ",".join([str(r.id) for r in paged_reports.object_list])
},
order_by=['sub_count']
)
但这仍然无效。我为所有报告提供了一个静态订阅者数量。我错过了什么,也许有更好的方法来实现这一目标?感谢
答案 0 :(得分:1)
我不能给你一个明确的答案,我相信你的问题是,即使在分页时,你的整个查询也必须执行,以便分页器知道有多少页面。我认为你最好在分页之前摆脱注释:
filter_search = ReportFilter(request.GET, queryset=Report.objects.filter(
created_at__gt=start_date,
created_at__lte=end_date,
is_confirmed__exact=True,
).order_by('-sub_count'))
paginator = Paginator(filter_search, 20)
result = paginator.page(1).object_list.annotate(
sub_count=Count("reportsubscriber"))
我相信您的示例object_list
是一个可以annotate
的查询集,但如果它只是list
个对象,您可以使用以下内容对每个结果页面进行注释:
pageIds = [report.id for report in paginator.page(1).object_list]
result = Report.objects.filter(id__in=pageIds).annotate(
sub_count=Count("reportsubscriber"))
但这都是在黑暗中拍摄的。你所做的一切都看起来太疯狂,所以除非你的数据集很大,否则我只能想象你的问题是一个索引不佳的查询。您真的想要分析正在生成的实际查询。您可以通过从项目Django shell执行给定的start_date
和end_data
来获取SQL:
Report.objects.filter(
created_at__gt=start_date,
created_at__lte=end_date,
is_confirmed__exact=True,
).order_by('-sub_count').query
然后使用EXPLAIN从数据库的PSQL命令行运行相同的查询。你必须做一些阅读才能弄清楚如何解释结果。
答案 1 :(得分:0)
好的,明白了。我选错了桌子。
所以我改变了.extra(),现在每页只有COUNTing:
result = filter_search.qs.extra(
select={
'sub_count': 'SELECT COUNT(*) FROM report_subscribers \
WHERE report_subscribers.report_id = reports.id\
AND report_subscribers.report_id IN %s \
' % "(%s)" % ",".join([str(r.id) for r in paged_reports.object_list])
}
)
但现在我无法按sub_count排序,因为我没有所有值。好吧,也许没有任何其他方法可以不计算数据库中的所有或实际存储计数
答案 2 :(得分:0)
这就是我使用Paginator进行过滤和基于类的视图的方法:
from django.core.paginator import Paginator, EmptyPage, InvalidPage
class BaseTemplateView(TemplateView):
"""
Abstract View to populate NavBar context
"""
def get_context_data(self, **kwargs):
context = super(BaseTemplateView, self).get_context_data(**kwargs)
context['ideas'] = Idea.objects.all()
return context
class IdeaView(BaseTemplateView):
template_name = 'products/idea.html'
def get(self, request, *args, **kwargs):
ideas = Idea.objects.all()
idea = get_object_or_404(Idea, slug=kwargs['slug'])
products = Product.objects.filter(ideas=idea)
products_list = products
paginator = Paginator(products_list, 12)
try:
page = int(request.GET.get('page', '1'))
except:
page = 1
try:
products = paginator.page(page)
except(EmptyPage, InvalidPage):
products = paginator.page(paginator.num_pages)
return render_to_response(self.template_name,
{'ideas': ideas, 'idea': idea, 'products': products},
context_instance=RequestContext(request))