Как я могу сделать это с помощью агрегации в django

#python #django #django-models

Вопрос:

У меня есть метод в модели, который сохраняет окончательную цену в корзине, это выглядит так:

 class Cart(models.Model):
    """Cart"""

    owner = models.OneToOneField('Customer', on_delete=models.CASCADE)
    meals = models.ManyToManyField(CartMeal, related_name='related_cart', blank=True)
    total_products = models.PositiveIntegerField(default=0)
    final_price = models.DecimalField(max_digits=9, decimal_places=2, default=0)
    in_orders = models.BooleanField(default=False)
    for_anonymous_user = models.BooleanField(default=False)


    def save(self, *args, **kwargs):
        if self.id:
            self.total_products = self.meals.count()
            self.final_price = sum([cmeals.final_price for cmeals in self.meals.all()])
        super().save(*args, **kwargs)
 

Мне сказали, что я могу создать эту строку self.final_price = sum([cmeals.final_price for cmeals in self.meals.all()]) с помощью одного запроса, используя aggregate.

Как я могу это сделать и где? В модели или мне нужно сделать это в представлении? Спасибо.

Ответ №1:

 Cart.objects.aggregate(
    final_price=Sum(F('meals__final_price'), 
    output_field=IntegerField()
)
# returns ->
{'final_price': 10}
 

Я бы предложил не хранить его в БД, а создать свойство в модели

 @property
def final_price(self):
    return self.meals.aggregate(
        final_price=Sum(F('final_price'), 
        output_field=IntegerField()
    )["final_price"]
 

Он может быть доступен так же, как поле:

 my_cart.final_price
 

Комментарии:

1. Спасибо за ответ. Но я получаю ошибку ["“{'final_price': Decimal('12.74')}” value must be a decimal number."] даже после того, как написал ее output_field Десятичное поле