2016-10-19 3 views
0

これらの値を持たないユーザーとの関連値の合計を加算したいと思います。Djangoクエリーセットの奇妙な動作

people_with_points = Person.objects.\ 
     filter(answer__correct=True).\ 
     annotate(points=Sum('answer__points')).\ 
     values('pk', 'points') 

<QuerySet [{'pk': 2, 'points': 190}, {'pk': 3, 'points': 150}]> 
:私は一人一人のためのポイントの合計を達成することができ、以下のクエリでは

Person | Answer.Points 
------ | ------ 
3  | 50 
3  | 100 
2  | 100 
2  | 90 

Person 4 has no answers and therefore, points 

class Answer(models.Model): 
    person = models.ForeignKey(Person) 
    points = models.PositiveIntegerField(default=100) 
    correct = models.BooleanField(default=False) 

class Person(models.Model): 
    # irrelevant model fields 

サンプルデータセット:ここ

は私のモデル構造の簡易版です

しかし、一部の人々は関連するAnswerのエントリがないかもしれないので、彼らはhav E 0点、私はそうのような「偽」そのポイントにCoalesceを使用し、以下のクエリで:私はUNION演算子を使用し

people_without_points = Person.objects.\ 
     exclude(pk__in=people_with_points.values_list('pk')).\ 
     annotate(points=Coalesce(Sum('answer__points'), 0)).\ 
     values('pk', 'points') 

<QuerySet [{'pk': 4, 'points': 0}]> 

意図したように、これらの作業のいずれもが、私は同じクエリセットでそれらを持っていると思います|はそれらを結合する:

everyone = people_with_points | people_without_points 

を今、問題のために:この後

、ポイントなしの人々が彼らのpoints値はになってい代わりにを入力してください。

<QuerySet [{'pk': 2, 'points': 190}, {'pk': 3, 'points': 150}, {'pk': 4, 'points': None}]> 

誰にもこのような現象が発生する理由はありますか?

ありがとうございます!

答えて

1

私は再びクエリセットに注釈を付けると、このように、0にnull値を合体することにより、その問題を解決できることを言及する必要があります:

everyone.\ 
    annotate(real_points=Concat(Coalesce(F('points'), 0), Value(''))).\ 
    values('pk', 'real_points') 

<QuerySet [{'pk': 2, 'real_points': 190}, {'pk': 3, 'real_points': 150}, {'pk': 4, 'real_points': 0}]> 

しかし、私は私が期待通りに労働組合が動作しない理由を理解したいです私の元の質問。

編集: 私はそれを持っていると思います。友人が私にdjango-debug-toolbarを使って私のSQLクエリをチェックしてこの状況をさらに調べるように指示しました。

2つのクエリの和集合であるため、2番目のクエリアノテーションは何らかの形で考慮されず、COALESCEを0にします使用されていません。これを最初のクエリに移動することによって、2番目のクエリに伝播され、期待される結果が得られます。

# Moved the "Coalesce" to the initial query 
people_with_points = Person.objects.\ 
    filter(answer__correct=True).\ 
    annotate(points=Coalesce(Sum('answer__points'), 0)).\ 
    values('pk', 'points') 

# Second query does not have it anymore 
people_without_points = Person.objects.\ 
    exclude(pk__in=people_with_points.values_list('pk')).\ 
    values('pk', 'points') 

# We will have the values with 0 here! 
everyone = people_with_points | people_without_points 

基本的に、私は次のように変更しました