11

Djangoアプリで次のコードを使用します。

pictures = gallery.picture_set.annotate( score=models.Sum( 'picturevote__value' ) ).order_by( '-score' )

ギャラリーのテーブルがあります。それらのそれぞれにいくつかの写真があります。ユーザーが画像に賛成または反対票を投じると、「picturevote」の新しい行が挿入され、画像に接続されます。次に、写真の合計スコアを取得できます。次に、1つのギャラリーの写真をスコア値で並べ替えます。ただし、テーブルの結合により、投票がまったくなかった場合、スコアの値がNULLになる可能性があります。それでも、スコア「NULL」は「0」として扱われます。

何か案は?

編集:さて、ここでいくつかの追加の説明:問題は、上記の例の集計がscoreNULLに設定されることです。スコアを表示したいときは、次のようなものを使用します。

score = self.picturevote_set.aggregate( models.Sum( 'value' ) )[ 'value__sum' ] or 0

次に、集計により、NULL(picturevote行がない場合)または特定の値が生成されます。NULLの場合、or式は表示可能な整数値に変換します。しかし、これはNULL値によって引き起こされる表示の問題だけを解決します。最初のコード例のようにこの値で画像を並べ替えたい場合score、NULLのすべてのエントリが順序付けられた結果セットの最後に配置されます。最初に正のスコアの画像があり、次に負の値の画像があり、次に、がNULLであるため、これまで投票されなかった画像がありますscore

私の質問は、順序が正しくなるようにこの動作をどのように変更できるかです。

4

3 に答える 3

20

Django 1.8 から、Coalesceデータベース機能があります。クエリは次のようになります。

from django.db.models.functions import Coalesce    

score = self.picturevote_set.aggregate(Coalesce(models.Sum('value'), 0))
于 2015-09-23T07:03:28.477 に答える
15

extraアノテーションが導入される前は、このようなことをしていたかもしれません。これは、投票がない場合に返されるはずだと思います(特定のデータベース実装がない場合は、少なくとも必要な関数を直接挿入できます)。 call - - このメソッドを使用):0COALESCECOALESCE(SUM(value), 0)

pictures = gallery.picture_set.extra(
    select={
        'score': 'SELECT SUM(value) FROM yourapp_picturevote WHERE yourapp_picturevote.picture_id = yourapp_picture.id',
    },
    order_by=['-score']
)

独自の SQL を新しい注釈に追加する組み込みの方法はわかりませんが (個人的にはまだ使用していません)、次のように新しい注釈を作成できるはずです。

from django.db.models import aggregates
from django.db.models.sql import aggregates as sql_aggregates

class SumWithDefault(aggregates.Aggregate):
    name = 'SumWithDefault'

class SQLSumWithDefault(sql_aggregates.Sum):
    sql_template = 'COALESCE(%(function)s(%(field)s), %(default)s)'

setattr(sql_aggregates, 'SumWithDefault', SQLSumWithDefault)

django.db.models.sql.aggregatesこれは、SQL 集約クラスのルックアップ方法のために新しい集約をモンキーパッチする必要があるため、かなり醜いように見えますが、ここで行ったのは、サブクラス化する新しい集約を追加Sumし、関数の呼び出しをハードコーディングしCOALESCE、プレースホルダーを追加したことだけです。これは、キーワード引数として指定する必要があります(少なくとも、この非常に基本的な実装例では)。

これにより、次のことができるようになります。

pictures = gallery.picture_set.annotate(score=SumWithDefault('picturevote__value', default=0).order_by('-score')
于 2009-02-17T11:30:34.553 に答える