2011-11-30 104 views
1

在Django的數據庫查詢優化新手問題:Django的數據庫查詢優化

我有一個自定義模式表單編輯一個目標對象,我在構造函數中,我得到一個QuerySet的持有從相關訪客模式,具有多對多字段到目的地(見編輯使用自定義模型形式的原因)

print "loading initial choices" 
    visitor_choices, visitor_initial = [], [] 
    visitor_set = self.instance.visitor_set.all() 
    print visitor_set 
    for obj in Visitor.objects.all(): 
     visitor_choices.append((obj.pk, obj.name)) 
     #if visitor_set.filter(pk=obj.pk # this hits the db every time! 
     if obj in visitor_set: 
      visitor_initial.append(obj.pk) 

    self.fields['visitors'].choices = visitor_choices 
    self.fields['visitors'].initial = visitor_initial 

    print "finished loading initial choices" 

的想法是相關visitor_set加載到一個變量,以避免重複的查詢,以檢查是否每個訪問者存在於visitor_set。這是最好的方法嗎?我可以看到一個重複的查詢(第三個SELECT語句)選擇目標ID爲1的所有訪問者,但是這並不存在於我寫的代碼,它從哪裏來的?

loading initial choices 
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor" INNER JOIN "testapp_visitor_destinations" ON ("testapp_visitor"."id" = "testapp_visitor_destinations"."visitor_id") WHERE "testapp_visitor_destinations"."destination_id" = 1 LIMIT 21; args=(1, 
) 
[<Visitor: MIMA>, <Visitor: MIMO>, <Visitor: MIMU>] 
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor"; args=() 
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor" INNER JOIN "testapp_visitor_destinations" ON ("testapp_visitor"."id" = "testapp_visitor_destinations"."visitor_id") WHERE "testapp_visitor_destinations"."destination_id" = 1 ; args=(1,) 
finished loading initial choices 

EDIT

Destination的對象我指的是一個ManyToMany場的Visitor物體上的相關側。如果我的表單正在編輯Visitor對象本身,那麼Django會自動處理ManyToMany字段。但要在Destination的模型表單上執行此操作,我需要爲Visitor添加多選字段,並自定義__init__方法以加載它的選項和初始選擇。

問題不過是關於如何處理查詢集,以及神祕的第二個SQL加載多對多值,我也可以從外殼看到:

>>> from testapp.forms import DestinationForm 
>>> from testapp.models import Destination, Visitor 
>>> dest = Destination.objects.get(pk=1) 
(0.001) SELECT "testapp_destination"."id", "testapp_destination"."destination" FROM "testapp_destination" WHERE "testapp_destination"."id" = 
1 ; args=(1,) 
>>> destinationForm = DestinationForm(instance=dest) 
loading initial choices 
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor" INNER JOIN "testapp_visitor_destinations" ON ("testap 
p_visitor"."id" = "testapp_visitor_destinations"."visitor_id") WHERE "testapp_visitor_destinations"."destination_id" = 1 LIMIT 21; args=(1, 
) 
[<Visitor: MIMA>, <Visitor: MIMO>, <Visitor: MIMU>] 
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor"; args=() 
(0.000) SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor" INNER JOIN "testapp_visitor_destinations" ON ("testap 
p_visitor"."id" = "testapp_visitor_destinations"."visitor_id") WHERE "testapp_visitor_destinations"."destination_id" = 1 ; args=(1,) 
finished loading initial choices 
>>> 

感謝

+1

你能解釋你想達到什麼嗎?對我來說,如果你爲其中'visitor'是'ManyToManyField'的模型生成一個'ModelForm',你就會默認做django應該做的事情? –

+0

是的,你是對的,我的表單試圖保存一個'目的地'模型,它位於我的'訪問者'模型的ManytoMany字段的相關端,我將發佈模型來澄清。所以我可以有一個表格來保存'訪問者',它會自動處理ManyToMany,但是我想要探索這種做法。然而,我的問題是關於我處理查詢集的方式,以及我在日誌中看到的奇怪的附加sql語句 – xuloChavez

回答

1

要回答什麼你說是你的問題:我想查詢

SELECT "testapp_visitor"."id", "testapp_visitor"."name" FROM "testapp_visitor" INNER JOIN "testapp_visitor_destinations" ON ("testapp_visitor"."id" = "testapp_visitor_destinations"."visitor_id") WHERE "testapp_visitor_destinations"."destination_id" = 1 ; args=(1,) 

來自行

if obj in visitor_set: 

其中Django的重新執行的visitor_set查詢(參見Django文檔When QuerySets are evaluated)。您可以避免通過轉換visitor_setset馬上(這樣的Django被迫立即執行查詢),如:

visitor_set = set(self.instance.visitor_set.all()) 

這也將一個對象是否在這組提高測試的性能(與list或類似的迭代相比)。