2016-08-11 14 views
3

は、私が2つのM2Mフィールドを持つモデルtestを持つオブジェクト。Djangoはプリフェッチを使用した複数の注釈が

私はこれらの関連フィールドの条件付きカウントに注釈を付けること、つまり特定の条件を満たす関連オブジェクトを数えようとしています。クエリーセットの外でこの情報を取得することはオプションではありません。なぜなら、注釈付きフィールドを使用して結果を並べ替える必要があるからです。

私は次のことを試してみた:プリフェッチを使用して

1. prefetch_relatedannotate後に適用されますので、これは、動作しません

from django.db.models import Prefetch, Count 

prefetch_foo = Prefetch('foo_set', queryset=foo.objects.filter(<some condition>)) 
prefetch_bar = Prefetch('bar_set', queryset=bar.objects.filter(<some condition>)) 
result = test.objects.prefetch_related(prefetch_foo, prefetch_bar).annotate(n_foo=Count('foo'), n_bar=Count('bar')) 

オブジェクト。

2.使用条件式これは、複数のSum注釈にこのバグのために動作しません

from django.db.models import Sum, Case, When 
from django.db.models.fields import IntegerField 

foo_sum = Sum(Case(When(foo__<some condition>, then=1), default=0, 
         output_field=IntegerField()))) 
bar_sum = Sum(Case(When(bar__<some condition>, then=1), default=0, 
         output_field=IntegerField()))) 
result = test.objects.annotate(n_foo=foo_sum, n_bar=bar_sum) 

sql = "SELECT SUM(CASE WHEN foo.<condition> " 
     "THEN 1 ELSE 0 END) FROM app_test " 
     "LEFT OUTER JOIN app_foo " 
     "ON (app_test.id = foo.test_id) " 
     "GROUP BY test.id" 
result = test.objects.annotate(n_foo=RawSQL(sql, [])) 
# Same method for bar 

RawSQL

使用 https://code.djangoproject.com/ticket/10060

3私はここで立ち往生しています。これはすべての行がで、"WHERE test.id = <ID of the object the annotation corresponds to>"のようなものを追加する方法が見つかりません。

カスタムSQLから正しい1行を取得する方法はありますか?または別の回避策ですか?

答えて

0

Django ORM(その8歳のバグのため)で行うことはできますが、RawSQLでHAVINGを使用するとうまくいくはずです。このようなことを試しましたか?

sql = """SELECT SUM(CASE WHEN app_foo.<condition> 
     THEN 1 ELSE 0 END) FROM app_test 
     LEFT OUTER JOIN app_foo 
     ON (app_test.id = app_foo.test_id) 
     GROUP BY app_test.id 
     HAVING app_test.id = <ID of the object the annotation corresponds to>""" 

T

+0

'django.db.models.F'は' RawSQL'内部には使用できませんので、私にはできませんよSQL文字列のオブジェクトの属性 – Filly

0

私はあなたのSQLに変更を加えました。あなたはapp_testを取得するためにFROMを使用しません。前にSQLサブクエリを見たことがありますか?

sql = """ 
    SELECT SUM(CASE WHEN app_foo.<condition> THEN 1 ELSE 0 END) 
    FROM app_foo 
    WHERE app_test.id = app_foo.id # app_test comes from outside the sub query. 

    """ 
result = test.objects.annotate(n_foo=RawSQL(sql, [])) 

実行します実際のクエリは、のようになります...

SELECT app_test.*, (
    SELECT SUM(CASE WHEN app_foo.<condition> THEN 1 ELSE 0 END) 
    FROM app_foo 
    WHERE app_test.id = app_foo.id ) AS n_foo 
FROM app_test 
関連する問題