Django общая стоимость OrderItems в корзине

Как я могу получить "общую" цену элементов OrderItem в модели cart из этих моделей ниже? Я пытался сделать кое-что в представлениях, но получаю ошибку атрибута, что объект QuerySet' не имеет атрибута 'total'.

views.py

def cart(request):
    cart = Cart.objects.filter(order_user=request.user)
    order_items = OrderItem.objects.filter(cart__in=cart)
    total = 0
    for i in order_items:
        total = i.quantity * i.item.price + cart.total
        cart.update(total=total)

models.py

    class OrderItem(models.Model):
        cart = models.ForeignKey('Cart', on_delete=CASCADE, null=True)
        item = models.ForeignKey(Item, on_delete=CASCADE, null=True)
        quantity = models.IntegerField(default=1)

class Item(Visits, models.Model):
    title = models.CharField(max_length=150)
    price =  models.IntegerField(default=1000)
    image = models.ImageField(upload_to='pictures', default='static/images/man.png')
    description = models.TextField(default="Item")
    visits = models.IntegerField(default=0)



class Cart(models.Model):
    order_user = models.OneToOneField(User, on_delete=CASCADE)
    ordered = models.BooleanField(default=False)
    total = models.IntegerField(default=0, help_text="100 = 1EUR")
    order_items = models.ManyToManyField(Item, related_name='carts', through=OrderItem )

Проблема возникает в первой строке внутри цикла for, где вы написали:

total = i.quantity * i.item.price + cart.total

Здесь корзина является QuerySet, поскольку вы использовали filter, когда извлекали объект cart из модели Cart в первой строке метода cart. filter возвращает QuerySet, а не объект. Вы можете использовать get для получения объекта cart, поскольку между моделями Cart и User существует отношение OneToOne. Попробуйте сделать это в первой строке вашего метода cart:

cart = Cart.objects.get(order_user=request.user)

Вы также должны использовать метод save вместо update, когда хотите обновить объект. Метод update принадлежит только QuerySet.

Вы можете получить общее количество через .annotate(…) [Django-doc] и таким образом вычислить его на стороне базы данных:

from django.db.models import F, Sum

def cart(request):
    cart = Cart.objects.annotate(
        price=Sum(F('orderitem__item__price') * F('orderitem__quantity'))
    ).get(
        order_user=request.user
    )
    cart.total = cart.price
    cart.save()
    # …

Возникающий при этом объект cart будет иметь дополнительный атрибут .price, содержащий цену товаров, умноженную на соответствующее количество.

Но это также указывает, почему вы должны не держать поле total в вашем Cart: вы можете вычислить его, когда это необходимо.

Вернуться на верх