2013-08-01 72 views
3

我有對象報告和ReportSubscriber,我想統計報告的訂閱者數量。Django過濾器,分頁和標註分頁結果

一種解決方案是註釋。我有很多的報告,以便註釋所有的人都需要〜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'] 
     ) 

但這仍然沒有奏效。我爲所有報告獲得了一個靜態數量的訂閱者。我錯過了什麼,也許有更好的方法來實現這個目標?謝謝

回答

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是一個QuerySet,你可以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_dateend_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命令行相同的查詢。你必須做一些閱讀才能弄清楚如何解釋結果。

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,因爲我不知道所有的值。那麼,也許沒有任何其他的方式來做到這一點,沒有計算所有或實際存儲在數據庫中的計數

0

這是我所使用的分頁程序具有過濾和基於類視圖:

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))