5

我有对象报告和报告订阅者,我想计算报告的订阅者数量。

一种解决方案是注释。我有很多报告,因此对所有报告进行注释大约需要 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']
        )

但这仍然没有奏效。我为所有报告获得了一个静态订阅者数量。我错过了什么,也许有更好的方法来实现这一点?谢谢

4

3 回答 3

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_dateand来获取 SQL end_data

Report.objects.filter(
        created_at__gt=start_date,
        created_at__lte=end_date,
        is_confirmed__exact=True,
    ).order_by('-sub_count').query

然后使用EXPLAIN从数据库上的 PSQL 命令行运行相同的查询。你必须做一些阅读来弄清楚如何解释结果。

于 2013-08-01T02:20:58.490 回答
0

好的,我知道了。我选择了错误的表。

所以我改变了 .extra() ,现在它只是每页计数:

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 排序,因为我没有所有的值。好吧,如果不计算全部或实际将计数存储在数据库中,也许没有其他方法可以做到这一点

于 2013-08-01T02:20:51.507 回答
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))
于 2014-02-05T13:52:23.153 回答