Home > Software design >  How can I get a total price column for CartItem model?
How can I get a total price column for CartItem model?

Time:12-01

class Product(models.Model):
    name = models.CharField(max_length=80)
    product_image = models.ImageField(upload_to='product/product/images/%Y/%m/%d/', blank=True)
    price = models.IntegerField()
class Cart(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
class CartItem(models.Model):
  item = models.ForeignKey(Product, null=True, on_delete=models.CASCADE)
  qty = models.IntegerField(default=1)
  cart = models.ForeignKey(Cart, null=True, on_delete=models.CASCADE)

I'm trying to get an automatic total price that will be shown on check out page. I want to add a 'total_price' column on CartItem model and set the default 'item.price * qty', but when I tried to add this line to the class:

  total_price = models.IntegerField(default=item.price)

since default value for qty is 1 but I got AttributeError: 'ForeignKey' object has no attribute 'price' error.

I also tried add this to the class:

@property
def total_price(self):
  item = self.object.get(product=self.item)
  return self.item.price

but I'm not sure which model will have the property? And when I added this method, I lost total_price column which I set its default as 0. I apologize for the lacking quality of solutions!

CodePudding user response:

You are in right direction. You can try annotation or aggregation to get the total price. Here is one approach:

For all Cart Items using annotation with Sum:

Cart.objects.all().annotate(total_spent=Sum(
                    F('cartitem__item__price') * 
                    F('cartitem__qty'),   
                    output_field=models.FloatField()
                ))

For one Cart, you can try like this with aggregation:

class Cart(...):
   ....

    @property
    def total_price(self):
      return self.cartitem_set.aggregate(price=Sum(
                        F('item__price') * 
                        F('qty'),   
                        output_field=models.FloatField()
                        )['price']

CodePudding user response:

Change the total_price property to:

 class CartItem(models.Model):
    cart = models.ForeignKey(Cart, null=True, on_delete=models.CASCADE, 
    related_name="orders") 
    
    @property
    def total_price(self):
        return self.qty * self.item.price

And you can easily get the total price of the Order Item.

If you want to get Total amount of all CartItems prices can do like below:

class Cart(models.Model):

    @property
    def total_amount(self):
        self.orders.annotate(total_spent=Sum(
                F('item__price') * 
                F('qty'),   
                output_field=models.FloatField()
            ))
  • Related