実際には、集計機能の一部をサブクラス化することでこれを行うことができます。これを本当に理解するにはコードを掘り下げる必要がありますが、 と で同様のことを行うためにコード化したものを次に示しMAX
ますMIN
。(注: このコードは Django 1.4 / MySQL に基づいています)。
基礎となる集計クラスをサブクラス化し、as_sql メソッドをオーバーライドすることから始めます。このメソッドは、実際の SQL をデータベース クエリに書き込みます。正しく渡されるフィールドを引用符で囲み、適切なテーブル名に関連付ける必要があります。
from django.db.models.sql import aggregates
class SqlCalculatedSum(aggregates.Aggregate):
sql_function = 'SUM'
sql_template = '%(function)s(%(field)s - %(other_field)s)'
def as_sql(self, qn, connection):
# self.col is currently a tuple, where the first item is the table name and
# the second item is the primary column name. Assuming our calculation is
# on two fields in the same table, we can use that to our advantage. qn is
# underlying DB quoting object and quotes things appropriately. The column
# entry in the self.extra var is the actual database column name for the
# secondary column.
self.extra['other_field'] = '.'.join(
[qn(c) for c in (self.col[0], self.extra['column'])])
return super(SqlCalculatedSum, self).as_sql(qn, connection)
次に、一般モデル集約クラスをサブクラス化し、add_to_query メソッドをオーバーライドします。このメソッドは、基になるクエリ オブジェクトに集計を追加する方法を決定します。フィールド名 (例: ) を渡して、対応する DB 列名を取得できるようにしたいqueue
(それが何か違う場合に備えて)。
from django.db import models
class CalculatedSum(models.Aggregate):
name = SqlCalculatedSum
def add_to_query(self, query, alias, col, source, is_summary):
# Utilize the fact that self.extra is set to all of the extra kwargs passed
# in on initialization. We want to get the corresponding database column
# name for whatever field we pass in to the "variable" kwarg.
self.extra['column'] = query.model._meta.get_field(
self.extra['variable']).db_column
query.aggregates[alias] = self.name(
col, source=source, is_summary=is_summary, **self.extra)
次に、次のような注釈で新しいクラスを使用できます。
queryset.annotate(calc_attempts=CalculatedSum('attempts', variable='queue'))
attempts
フィールドとフィールドの db 列名が同じであると仮定するとqueue
、次のような SQL が生成されます。
SELECT SUM(`LogQuarter`.`attempts` - `LogQuarter`.`queue`) AS calc_attempts
そして、そこに行きます。