4

Django 1.4.4 で奇妙な問題が発生しました。

私はこのモデルを持っています:

class LogQuarter(models.Model):
  timestamp = models.DateTimeField()
  domain = models.CharField(max_length=253)
  attempts = models.IntegerField()
  success = models.IntegerField()
  queue = models.IntegerField()
  ...

sent プロパティが高い最初の 20 個のドメインを収集する必要があります。送信されたプロパティは試行 - キューです。

これは私の要求です:

obj = LogQuarter.objects\
      .aggregate(Sum(F('attempts')-F('queue')))\
      .values('domain')\
      .filter(**kwargs)\
      .order_by('-sent')[:20]

私もextraで試しましたが、うまくいきません。

これは本当に基本的な SQL です。Django がこれを実行できないことに驚いています。

誰かが解決策を持っていましたか?

4

2 に答える 2

4

実際には、集計機能の一部をサブクラス化することでこれを行うことができます。これを本当に理解するにはコードを掘り下げる必要がありますが、 と で同様のことを行うためにコード化したものを次に示し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

そして、そこに行きます。

于 2013-10-22T23:00:39.700 に答える
0

これができるかどうかわかりませんSum(F('attempts')-F('queue'))。最初にエラーをスローする必要があります。もっと簡単な方法は、extra を使用することだと思います。

result = LogQuarter.objects.extra(select={'sent':'(attempts-queue)'}, order_by=['-sent'])[:20]
于 2012-12-17T17:06:18.263 に答える