2015-10-22 79 views
0

我有其中「可變模板」的定義,和連接到每一個位置模型在數據庫中,產生這些變量的實例的2維陣列的模型。的Django - 迭代一個查詢集產生數百查詢

class Location(models.Model): 
    name = models.CharField(max_length=4, blank=False, unique=True) 

class LocationVariableDefinition(models.Model): 
    name = models.CharField(max_length=32, blank=False, unique=True) 
    type = models.CharField(max_length=60, default="text") 
    default_value = models.CharField(max_length=250, blank=True, default="[UNSET]") 

class LocationBasedVariable(models.Model): 
    location = models.ForeignKey(Location) 
    definition = models.ForeignKey(LocationVariableDefinition, default=None) 

    value = models.CharField(max_length=250, blank=True) 

要編輯這些變量,我有一個單頁有一張桌子,變量名倒邊,並沿頂位置。我添加了一個新的SimpleTag的,讓我從字典中之快譯通訪問值,並認爲產生這個字典:

class VarListView(TemplateView): 
    template_name = "lbv-list.html" 

    def locations(self): 
     return Location.objects.all() 

    def locvars(self): 

     dict = {} 

     for v in LocationBasedVariable.objects.all(): 
      dict.setdefault(v.location.id, {}) 
      dict[v.location.id][v.definition.id] = v.value 

     return dict 

    def locvarnames(self): 
     return LocationVariableDefinition.objects.all() 

,然後在模板:

<table class="table table-striped table-condensed striped"> 
     <thead> 
     <tr> 
      <th>&nbsp;</th> 
      {% for loc in view.locations %} 
       <th>{{ loc.name }}</th> 
      {% endfor %} 
     </tr> 
     </thead> 
     <tbody> 
     {% for lv in view.locvarnames %} 
      <tr> 
       <th>{{ lv.name }}</th> 
       {% for loc in view.locations %} 
        <td>{% get_dictitem2 view.locvars loc.id lv.id%}</td> 
       {% endfor %} 
      </tr> 
     {% endfor %} 
     </tbody> 
    </table> 

所有作品,除了有3個位置和5個變量,我得到 SQL查詢,需要大約3秒,我的筆記本電腦上運行。

我能做些什麼來改善呢?我一直認爲查詢集會被緩存,但在控制檯中記錄的SQL似乎一遍又一遍地讀取相同的集合。有沒有提示我可以給Django結果不會改變,或者只有一次只做一次查詢的方法?

或者我應該只是傳遞一個排序的查詢集的模板,並在那裏搞清楚的行和列? (我通常會做到這一點的方式將涉及保持狀態在模板的最後位置與當前進行比較,我不認爲我能做到這一點的模板)

+1

您可以通過將'.id'更改爲'_id'來開始減少查詢次數。看到[這個問題](http://stackoverflow.com/q/32869856/1324033)爲例.. – Sayse

+0

我想象下面給出的三個答案應該大大減少您的查詢量和執行時間.. – Sayse

+1

@ Sayse - 同意!我認爲真正的關鍵是我不知何故認爲view.locvars()只會被評估一次。我會回到實際創建一個上下文並添加到它,這是我通常會做的,除了我昨天發現這個整潔的博客文章... – AnotherHowie

回答

2

通常的做法是,一旦評估方法和結果get_context_data添加到模板上下文。

class VarListView(TemplateView): 
    def get_context_data(self, **kwargs): 
     # Call the base implementation first to get a context 
     context = super(VarListView, self).get_context_data(**kwargs) 
     context['locations'] = self.locations() 
     context['locvarnames'] = self.locavarnames() 
     context['locvars'] = self.locvars() 
     return context 

然後,在您的模板中,刪除view前綴,例如, locations而不是view.locations

1

你有幾個選擇這裏,但我認爲最好的是使用_id屬性來處理您的外鍵關係。 Django的存儲有問題的模型外鍵的ID,所以你的情況,你可以取代你的循環:

for v in LocationBasedVariable.objects.all(): 
    dict.setdefault(v.location_id, {}) 
    dict[v.location_id][v.definition_id] = v.value 

這意味着你將不必查詢相關的表只是爲了獲得ID 。

此外,它看起來像你調用{% get_dictitem2 view.locvars loc.id lv.id%}view.locvarnames中的每個項目,然後將轉到數據庫,加載所有的LocationBasedVariable和填充該字典。

我可能會嘗試緩存在視圖中,所以你只能填充一次:更改.id_id

class VarListView(TemplateView): 
    template_name = "lbv-list.html" 
    _location_based_variable_cache = None 

    def locations(self): 
     return Location.objects.all() 

    def locvars(self): 

     if not self._location_based_variable_cache: 
      self._location_based_variable_cache = {} 

      for v in LocationBasedVariable.objects.all(): 
       self._location_based_variable_cache.setdefault(v.location_id, {}) 
       self._location_based_variable_cache[v.location_id][v.definition_id] = v.value 

     return self._location_based_variable_cache 

    def locvarnames(self): 
     return LocationVariableDefinition.objects.all() 
1

除此之外,你也應該看你真正需要返回,因爲你的for循環永遠只能使用ID,你可以只使用values過濾此下手

query_gives_locations.values('id') 

你必須繼續得到每次.locvars這樣你就可以移動這個外

{% with locvars=view.locvars %} 
{% for loc in view.locations %} 
     <td>{% get_dictitem2 locvars loc_id lv_id%}</td> 

{% endfor %} 
{% endwith %} 
+0

你也可以玩'prefetch_related'和類似的.. – Sayse