Kay
Kay

Reputation: 881

Django total price of OrderItems in Cart

How can I get "total" price of items of OrderItem in cart model from these models down below? I tried doing something in views but I get attribute error that QuerySet object has no attribute '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 )

Upvotes: 2

Views: 1737

Answers (3)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476709

You can get the total through .annotate(…) [Django-doc] and thus calculate this at the database side:

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()
    # …

The cart object that arises from this will have an extra attribute .price that contains the price of the items multiplied with the corresponding quantity.

But this also specifies why you should not keep a total field in your Cart: you can calculate that when necessary.

Upvotes: 2

Mallu developer
Mallu developer

Reputation: 86

class OrderItem(DateTimeModel):
    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="order_items")
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField(default=1, blank=True, null=True)
    price = models.DecimalField(max_length=100, default=0, max_digits=7, decimal_places=2)
    total = models.DecimalField(max_digits=7, decimal_places=2, default=0)
# need to add tax percentage along with it tax may be changed in future so we need to add tax percentage in this

def __str__(self):
    return f"{self.id} - {self.order}"

def get_total(self):
    return round(float(self.price) * float(self.quantity))

def save(self, *args, **kwargs):
    self.total = self.get_total()
    super().save(*args, **kwargs)

Upvotes: 0

Safiul Kabir
Safiul Kabir

Reputation: 164

The problem is coming from the first line inside the for loop where you've written:

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

Here, the cart is a QuerySet since you've used filter when you retrieved the cart object from Cart model in the first line of cart method. filter returns QuerySet, not object. You can use get to get the cart object since there is a OneToOne relationship between the Cart and User models. Try this in the first line of your cart method:

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

You also need to use save method instead of update when you want to update an object. update method belongs to QuerySet only.

Upvotes: 0

Related Questions