web-dev-qa-db-ja.com

乗算された2つのフィールドの合計に注釈を付けます

例として簡略化された3つのモデルがあります。

_class Customer(models.Model):
    email = models.CharField(max_length=128)

class Order(models.Model):
    customer = models.ForeignKey(Customer)
    order_status = models.CharField(blank=True, max_length=256)

class Lineitem(models.Model):
    order = models.ForeignKey(Order)
    quantity = models.IntegerField(blank=True)
    price = models.DecimalField(max_digits=6, decimal_places=2)
_

顧客に(おそらくフィルターを使用して)クエリを実行し、顧客が費やした合計(つまり、(価格*数量)の合計)に注釈を付けたい

私が試してみました:
Customer.objects.filter(something).annotate(total_spent=Sum(F('order__lineitem__quantity') * F('order__lineitem__price')))

Sum()はF()式では使用できないようです。これを行う別の方法はありますか?

36
Sam

今はこの答えは必要ないかもしれませんが、 合計式 に関するドキュメントを読んだ場合は、次のようにoutput_fieldを宣言する必要があります。

Customer.objects.filter(something)
                .annotate(total_spent=Sum(
                    F('order__lineitem__quantity') * 
                    F('order__lineitem__price'),   
                    output_field=models.FloatField()
                ))
14
nelson orland

.extra()メソッドの使用を検討しましたか?

Django QuerySet API を参照してください。

1
Grant

LineItemモデルのプロパティを使用してみることができます。

class Lineitem(models.Model):
    order = models.ForeignKey(Order)
    quantity = models.IntegerField(blank=True)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    def _get_total(self):
        return quantity * price
    total = property(_get_total)

次に、使用した合計金額で注釈を付けることができると思います

Customer.objects.filter(something).annotate(total_spent=Sum('order__lineitem__total'))

このメソッドの効率が他のメソッドとどのように関連しているかはわかりませんが、SQLクエリ全体を次のように手動で記述するという代替方法よりもPythonic/Django-yです。

Customer.objects.raw("SELECT ... from <customer_table_name> where ...")
1
murgatroid99

おそらく、独自のカスタムアグリゲーターを展開する必要があります。ここから始めるためのGROUP_CONCATの例の簡単なウォークスルーを見つけることができます: http://harkablog.com/inside-the-Django-orm-aggregates.html

1
Chad

私はちょうどこれに遭遇しました、そして私は注釈を付けてプロパティで動作するとは思いません、 Django-集計関数のフィールドとしてプロパティを使用できますか? を参照してください

これが私がしたことです。

class Customer(models.Model):
    email = models.CharField(max_length=128)

class Order(models.Model):
    customer = models.ForeignKey(Customer)
    order_status = models.CharField(blank=True, max_length=256)

class Lineitem(models.Model):
    order = models.ForeignKey(Order)
    quantity = models.IntegerField(blank=True)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    @property
    def total(self):
        return self.quantity * self.price

次に、合計とリスト内包表記を使用します。

sum([li.total for li in  LineItem.objects.filter(order__customer=some_customer).filter(somefilter)])
0
Justin Hamade

類似: https://stackoverflow.com/a/19888120/1344647

from Django.db.models import Sum

q = Task.objects.filter(your-filter-here).annotate(total=Sum('progress', field="progress*estimated_days"))

編集:@Maxのおかげで、代わりにアノテートを使用して集約されました。

0
Ali