Django コードと Django バグ レポートのリファレンス
次の 3 つのモデルが与えられます (デモンストレーションのために過度に単純化されています...実際には同一の関連モデルではありません)。
class derp(models.Model):
...
class derp_related_1(models.Model):
fk = models.ForeignKey(derp)
amount = models.DecimalField(max_digits=15, decimal_places=2)
class derp_related_2(models.Model):
fk = models.ForeignKey(derp)
amount = models.DecimalField(max_digits=15, decimal_places=2)
そして、次のようにモデル admin でクエリセットをオーバーライドします。(この django のバグのため、動作していません。)
class DerpAdmin(admin.ModelAdmin):
...
list_display = ['derp_r1_sum', 'derp_r2_sum']
...
def queryset(self, request):
qs = super(DerpAdmin, self).queryset(request)
qs = qs.annotate(derp_r1_sum=models.Sum('derp_r1__amount', distinct=True))
qs = qs.annotate(derp_r2_sum=models.Sum('derp_r2__amount', distinct=True))
def derp_r1_sum(self, obj):
return u'%s' % obj.derp_r1_sum
def derp_r2_sum(self, obj):
return u'%s' % obj.derp_r2_sum
予期しないデータベース結果の例
アノテーションを個別に実行すると、次のようにレンダリングされます(グループ化と合計が削除されます)
+---------+--------+
| derp.id | r1_sum |
+---------+--------+
| 2 | 500.00 |
| 2 | 100.00 |
+---------+--------+
r1_sum would be 600.00
and
+---------+--------+
| derp.id | r1_sum |
+---------+--------+
| 2 | 100.00 |
| 2 | 250.00 |
+---------+--------+
r2_sum would be 350.00
両方の注釈を含む qs.query を取得し、合計とグループ化を削除すると、問題が何であるかは明らかです。この場合、すべてを 2 回カウントしています。より多くの関係を取得すると、両方の合計列でますます醜い増加が見られます。
+---------+--------+--------+
| derp.id | r1_sum | r2_sum |
+---------+--------+--------+
| 2 | 500.00 | 100.00 |
| 2 | 500.00 | 250.00 |
| 2 | 100.00 | 100.00 |
| 2 | 100.00 | 250.00 |
+---------+--------+--------+
r1_sum would incorrectly be 1200.00
r2_sum would incorrectly be 700.00
質問、カスタム SQL 以外のルートはありますか?
私はクエリを自分で簡単に書くことができますが、誰かがカスタム SQL の作成を回避する提案があれば、それは素晴らしいことです.
助けてくれてありがとう。
編集:これは、Django ドキュメントの注釈セクションへのリンクです。1 人のコメント提出者は、個別のオプションについて言及しました。これは機能しません。django ドキュメントの注釈セクションの下部で警告されていると思います。
Edit2: derp.objects.raw('sql here') は、管理者が使用するために必要なクエリセット オブジェクトを返さないため、生の SQL のアイデアは思ったよりも難しい可能性があります。2 つのクエリ (実際のクエリセットと合計を行うカスタム クエリセット) を使用し、両方からリストビューを設定する方法はありますか? 私が見つけた1つの提案(今はもう見つけることができません:S)は、モデル定義にマップするビューを作成し、それをdjangoによって管理されないように設定することを提案しました(syncdb用)。その後、カスタム コードを記述し、それを参照して元のクエリに含めることができます。これは面倒ですね。考え?