0

Django で生のクエリの動作を理解するのに問題があります。問題は、RawQuerySet の使用中にデータベースへのクエリの数にあります。RawQuerySet を使用するたびに、新しいデータベース クエリが送信されるようです。たとえば、次のコードを使用します。

    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 からの追加の「ヘルプ」は必要ないように思えます。何か不足していますか?そのような場合にクエリを1つだけにする方法はありますか? 私は Reviews.objects.raw() を list() にキャストすることに決めたことを知っていますが、それは役に立ちますが、それでもなぜこのように行われるのか気になります。

4

1 に答える 1

0

問題はあなたのlist(reviews)表現から来ています - これにより、RawQuerySet は最初のクエリから何らかの方法で完全なモデル インスタンスを構築しようとします (おそらく最も効率的な方法ではありませんが、それは別の話です)。この行がなく、関連するオブジェクトにアクセスしていないと仮定すると、次のスニペットでわかるように、クエリは 1 つしか作成されません。

>>> 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)行はループ内のものだと思います-コピーアンドペーストエラーです(そうでない場合は、「平均」の定義についてもっと知りたいと思います)。次に、データベースに計算を依頼するために必要なクエリは 1 つだけです (ループも Python 計算も必要ありません)。生のSQLを使用してこれを行うことができます:

select avg(stars) from reviews;

または ORM の集計関数を使用する ( https://docs.djangoproject.com/en/1.4/topics/db/aggregation/を参照):

>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
于 2012-07-01T16:41:13.097 に答える