Pertanyaan Anotasikan jumlah dua bidang yang dikalikan


Saya memiliki tiga model, disederhanakan untuk contoh:

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)

Saya ingin menanyakan pelanggan (mungkin dengan filter) dan membubuhi keterangan total yang telah mereka habiskan (yaitu, jumlah di atas (harga * kuantitas)

Saya telah mencoba:
Customer.objects.filter(something).annotate(total_spent=Sum(F('order__lineitem__quantity') * F('order__lineitem__price')))

Akan muncul bahwa Sum () tidak dapat digunakan dengan F () ekspresi. Apakah ada cara lain untuk melakukan ini?


32
2018-04-30 17:46


asal


Jawaban:


Mungkin Anda tidak membutuhkan jawaban ini sekarang, tetapi jika Anda membaca dokumentasi tentangnya Ringkaskan ungkapan , Anda perlu menyatakan output_field, seperti ini:

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

7
2018-02-15 15:53



Pernahkah Anda melihat menggunakan .extra() metode?

Lihat API QuerySet Django.


1
2018-04-30 17:54



Anda dapat mencoba menggunakan properti di LineItem model:

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)

Maka saya pikir Anda dapat membubuhi keterangan dengan jumlah total yang dihabiskan menggunakan

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

Saya tidak tahu bagaimana efisiensi metode ini berhubungan dengan yang lain, tetapi lebih Pythonic / Django-y daripada alternatifnya, yaitu menulis seluruh kueri SQL dengan tangan seperti pada

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

1
2017-08-24 15:07



Anda mungkin harus menggulirkan agregator kustom Anda sendiri. Anda dapat menemukan jalan sederhana melalui GROUP_CONCAT contoh yang harus Anda mulai di sini: http://harkablog.com/inside-the-django-orm-aggregates.html


1
2017-10-16 21:56



Saya hanya berlari ke ini dan saya tidak berpikir bahwa membubuhi keterangan dan akan bekerja dengan properti, lihat Django - Dapatkah Anda menggunakan properti sebagai bidang dalam fungsi agregasi?

Inilah yang saya lakukan.

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

Kemudian gunakan penjumlahan dan pemahaman daftar:

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

0
2017-11-26 20:20



Mirip dengan: 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"))

Diedit: Terima kasih kepada @Max, menggunakan anotasi sebagai pengganti agregat.


0
2018-06-18 02:51