2012-07-01 16 views
0

我在理解Django中原始查詢的行爲時遇到問題。問題在於使用RawQuerySet時對數據庫的查詢數量。它看起來像我每次使用RawQuerySet時都會發送新的數據庫查詢。例如,使用此代碼:使用RawQuerySet在Django中進行懶惰查詢

reviews = Reviews.objects.raw('select * from reviews rv [...]') 

    count = len(list(reviews)) 
    avg_rating = 0.0 

    if count > 0: 
     for r in reviews: 
      avg_rating = avg_rating + r.stars  
      avg_rating = avg_rating/float(count) 

    avg_rating = avg_rating/float(count) 

每次使用「評論」會產生新的,相同的查詢。爲什麼RawQuerySet如此懶惰?在我看來,一旦有人決定使用原始查詢,他不需要從Django獲得額外的「幫助」。我錯過了什麼嗎?有沒有辦法在這種情況下只有一個查詢?我知道我決定把評論.objects.raw()轉換爲list(),它有幫助,但它仍然困擾着我爲什麼這樣做。

回答

0

問題來自您的list(reviews)表達式 - 這迫使RawQuerySet試圖以最簡單的方式從最初的查詢中構建完整的模型實例(可能不是最有效的方式,但這是另一個故事)。如果沒有這行,假設你沒有訪問相關的對象,就只有一個查詢做,因爲你可以在這個片段看到:

>>> from survey.models import Question 
>>> from django.db import connection 
>>> import pprint 
>>> connection.queries 
[] 
>>> raw = Question.objects.raw("select * from survey_question") 
>>> for q in raw: 
...  print q.id 
... 
1 
2 
3 
4 
>>> connection.queries 
[{'time': '0.000', 'sql': 'select * from survey_question'}] 
>>> list(raw) 
[<Question: Survey Essai1 (root) question #1 - Depuis combien de temps programmez vous ?>, <Question: Survey Essai1 (root) question #2 - Comment avez vous débuté ?>, <Question: Survey Essai1 (root) question #3 - Quel est votre niveau de formation>, <Question: Survey Essai1 (root) question #4 - Cette formation porte-t-elle sur l'informatique ?>] 
>>> pprint.pprint(connection.queries) 
[{'sql': 'select * from survey_question', 'time': '0.000'}, 
{'sql': 'select * from survey_question', 'time': '0.000'}, 
{'sql': 'SELECT `survey_survey`.`id`, `survey_survey`.`user_id`, `survey_survey`.`title`, `survey_survey`.`notes`, `survey_survey`.`description`, `survey_survey`.`instructions`, `survey_survey`.`date_created`, `survey_survey`.`starts_on`, `survey_survey`.`ends_on` FROM `survey_survey` WHERE `survey_survey`.`id` = 1 ', 
    'time': '0.001'}, 
{'sql': 'SELECT `auth_user`.`id`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`password`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`is_superuser`, `auth_user`.`last_login`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`id` = 1 ', 
    'time': '0.001'}, 
{'sql': 'SELECT `survey_survey`.`id`, `survey_survey`.`user_id`, `survey_survey`.`title`, `survey_survey`.`notes`, `survey_survey`.`description`, `survey_survey`.`instructions`, `survey_survey`.`date_created`, `survey_survey`.`starts_on`, `survey_survey`.`ends_on` FROM `survey_survey` WHERE `survey_survey`.`id` = 1 ', 
    'time': '0.000'}, 
{'sql': 'SELECT `auth_user`.`id`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`password`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`is_superuser`, `auth_user`.`last_login`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`id` = 1 ', 
    'time': '0.000'}, 
{'sql': 'SELECT `survey_survey`.`id`, `survey_survey`.`user_id`, `survey_survey`.`title`, `survey_survey`.`notes`, `survey_survey`.`description`, `survey_survey`.`instructions`, `survey_survey`.`date_created`, `survey_survey`.`starts_on`, `survey_survey`.`ends_on` FROM `survey_survey` WHERE `survey_survey`.`id` = 1 ', 
    'time': '0.000'}, 
{'sql': 'SELECT `auth_user`.`id`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`password`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`is_superuser`, `auth_user`.`last_login`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`id` = 1 ', 
    'time': '0.000'}, 
{'sql': 'SELECT `survey_survey`.`id`, `survey_survey`.`user_id`, `survey_survey`.`title`, `survey_survey`.`notes`, `survey_survey`.`description`, `survey_survey`.`instructions`, `survey_survey`.`date_created`, `survey_survey`.`starts_on`, `survey_survey`.`ends_on` FROM `survey_survey` WHERE `survey_survey`.`id` = 1 ', 
    'time': '0.000'}, 
{'sql': 'SELECT `auth_user`.`id`, `auth_user`.`username`, `auth_user`.`first_name`, `auth_user`.`last_name`, `auth_user`.`email`, `auth_user`.`password`, `auth_user`.`is_staff`, `auth_user`.`is_active`, `auth_user`.`is_superuser`, `auth_user`.`last_login`, `auth_user`.`date_joined` FROM `auth_user` WHERE `auth_user`.`id` = 1 ', 
    'time': '0.000'}] 
>>> 

現在的問題是:爲什麼要使用一個RawQueryset在所有的上面的計算?

我假設第一個avg_rating = avg_rating/float(count)行在循環中的一個 - 是一個複製粘貼錯誤(如果不是,我會很想知道更多關於您的「平均」的定義)。然後,您只需要一個查詢(不需要循環,也不需要python計算)來要求數據庫執行計算。你可以做到這一點無論使用原始的SQL:

select avg(stars) from reviews; 

或使用ORM的聚合功能(CF https://docs.djangoproject.com/en/1.4/topics/db/aggregation/):

>>> from django.db.models import Avg 
>>> Book.objects.all().aggregate(Avg('price'))