2015-10-31 88 views
0

當我加載我的菜單選項卡時,我有很多重複的查詢(在Django的調試工具欄),我確定我可以優化這個,但沒有找到好的方法。需要一些意見重複查詢

型號:

class Categorie(models.Model): 
    name = models.CharField(max_length=30) 
    visible = models.BooleanField(default = False) 

    def __str__(self): 
     return self.nom 

    def getscateg(self): 
     return self.souscategorie_set.all().filter(visible = True) 


class SousCategorie(models.Model): 
    name = models.CharField(max_length=30) 
    visible = models.BooleanField(default = False) 
    categorie = models.ForeignKey('Categorie') 

    def __str__(self): 
     return self.name 

    def gettheme(self): 
     return self.theme_set.all().filter(visible = True) 


class Theme(models.Model): 
    name = models.CharField(max_length=100) 
    visible = models.BooleanField(default = False) 
    souscategorie = models.ForeignKey('SousCategorie') 

    def __str__(self): 
     return self.name 

瀏覽:

def page(request): 
    categs = Categorie.objects.filter(visible = True) 

    return render(request, 'page.html', locals()) 

模板:

{% for categ in categs %} 

    <li> 
     {{categ.name}} 
     <ul> 
      {% for scateg in categ.getscateg %} 

       <li> 
        {{scateg.name}} 
        <ul> 

         {% for theme in scateg.gettheme %} 

          <li>{{ theme.name }}</li>  

         {% endfor %}     

        </ul>    
       </li> 

      {% endfor %} 
     </ul> 
    </li> 

{% endfor %} 

我看看prefetch_related但只有當我想從SousCategorie和SousCategorie從主題加載Categorie工作,所以如果我明白我需要與此相反......

回答

0

在Django中,每當您評估一個新的查詢集時執行查詢,因此您需要減少正在使用的查詢集的數量。這裏是正在發生的事情:

  • 您創建一個查詢集Categorie.objects.filter(visible=True),並傳遞到視圖層,還有第一個查詢在此標記{% for categ in categs %}
  • 在循環中執行,你每個類別調用一個方法categ.getscateg返回一個新的查詢集return self.souscategorie_set.all().filter(visible = True),這個查詢集將在第二循環在你的模板執行{% for scateg in categ.getscateg %}
  • 同樣的事情發生與{% for theme in scateg.gettheme %}

使用prefetch_related是明智之舉,嘗試像(沒有測試):

Categorie.objects.filter(visible=True, souscategorie_set__visible=True, souscategorie_set__theme_set__visible=True).prefetch_related('souscategorie_set__theme_set')

prefetch_related作品通過運行第一查詢加載滿足您的當前過濾器的類別,然後執行第二查詢加載所有子類別等。

在其他情況下,你可以使用select_related,但只能在一個單一的查詢可以使用,作爲一個例子,它會如果你需要一個主題的類別和子類別,如工作:

Theme.objects.filter(pk=1).select_related('souscategorie__categorie')

這裏的區別是主題是ForeignKey,所以它只有一個子類別,它可以加載一個單一的聯接,這意味着只有當您的查詢集來自模型時,您纔可以使用select_related點我認爲它也適用於OneToOneField

+0

謝謝您的回答,其實你的主張沒有爲我工作,我出現此錯誤:無法將關鍵字'souscategorie_set'解析爲字段。我嘗試用這種方法找到一種方法。其實在django調試工具欄我有105重複查詢105查詢,但他們大多數需要0ms執行,所以沒有影響在頁面加載,我想我應該發佈我的真實模板和查詢日誌揭露我的問題。 – V1ce

+0

我使用了你在問題中給出的信息,如果你得到這個錯誤的名稱是錯誤的,請在頁面上看看[訪問相關對象](https://docs.djangoproject.com/en/1.8/REF /模型/關係/)。 105個查詢是非常糟糕的,即使它現在以0ms運行,您應該嘗試修復它。另外,我建議閱讀[關於優化的文檔](https://docs.djangoproject.com/en/1.8/topics/db/optimization/) –

0

我必須使用「與」 2減少我查詢集

這是一個好點,但我總是有很多重複的(如44式兩份51個查詢),例如我打我的數據庫,當我這樣做即:

{% for categ in categs %} 
    {% with currscat=categ.getscateg %} 

     <li class = "{% if currscat %} has_menu {% endif %}"> {{categ.name}} # This line hit database 

      {% if currscat %} # This line hit database 

        <ul class = "menu-1"> ... </ul> 

      {% endif %} 

     </li> 

    {% endwith %} 
{% endfor %} 

我嘗試使用prefetch_related這樣的:

categs = Categorie.objects.filter(visible=True).prefetch_related('souscategorie_set') 

但是那只是添加查詢數據庫,不降低...

有些建議嗎?

謝謝

2

解決了!

如果它能夠幫助:

from .models import Categorie, SousCategorie, Theme, SousTheme 
from django.db.models import Prefetch 

pf_souscategorie = Prefetch('souscategorie_set', SousCategorie.objects.filter(visible=True)) 
pf_theme = Prefetch('souscategorie_set__theme_set', Theme.objects.filter(visible=True)) 
pf_soustheme = Prefetch('souscategorie_set__theme_set__soustheme_set', SousTheme.objects.filter(visible=True)) 

categs = Categorie.objects.filter(visible=True).prefetch_related(pf_souscategorie, pf_theme, pf_soustheme) 

,並在模板調用是這樣的:

{% with currscat=categ.souscategorie_set.all %} 
{% with currth=souscateg.theme_set.all %} 
{% with currsth=theme.soustheme_set.all %} 

再見