Hello I have a question I have no idea how can i get total price of not iterable object in Django, I get this error:
TypeError at /cart
'OrderItem' object is not iterable
Here is my code, I would be pleased by any advise.
views.py
order_items = OrderItem.objects.filter(cart=cart)
order_items = OrderItem.objects.annotate(
sum=Sum(F('item__price') * F('quantity'))
).get(cart=cart)
order_items.total_price = order_items.sum
order_items.save(force_update=True)
models.py
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 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)
total_price = models.IntegerField(default=1)
you can create function in you model and used The result on your view
like this:
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)
# does not needed
# total_price = models.IntegerField(default=1)
#property
def get_total(self):
total = self.item.price * self.quantity
return total
Related
I am getting alot of duplicates in my template when i try to call the calculated loan payments in templates.
My models:
class Client(models.Model):
full_name = models.CharField(max_length=200,blank=True) staff=models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.SET_NULL,null=True,blank=True,related_name="client")
date = models.DateTimeField(default=timezone.now)
class Loan(models.Model):
ref = ShortUUIDField(length=6,max_length=6,alphabet="ABCDZXFQFHKRKL0123456789",unique=True)
loan_amount = models.IntegerField(blank=True,null=True)
staff=models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.SET_NULL,null=True,blank=True,related_name="loans")
search_client=models.ForeignKey(Client,on_delete=models.SET_NULL,null=True,blank=True)
#cached_property
def loan_repayments(self):
myfilter = Loan.objects.filter(ref=self.ref,payment__payment_reason='loan repayment')
result=myfilter.aggregate(total=Sum(F('payment__amount')))
total = result['total']
if total is None:
return 0
return total
class Payment(models.Model):
ref = ShortUUIDField(length=6,max_length=6,alphabet="ABCDZXFQFHKRKL0123456789",unique=True)
payment_reason = models.CharField(max_length=200, null=True, blank=True,choices=PAYMENT_REASON,default='loan repayment',db_index=True)
amount = models.IntegerField(blank=True, null=True)
lender = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL,
blank=True, null=True, related_name="payments")
loan = models.ForeignKey(Loan, on_delete=models.CASCADE,
blank=True, null=True)
my view:
class Loan(LoginRequiredMixin,ListView):
query_set =Loan.objects.filter(status="active",action="creating loan").select_related('staff','search_client')
context_object_name = 'transactions'
paginate_by = 15
my template:
duplicates am getting:
duplicates in the toolbar
I am trying to create a case where when I call the order create api, the price will be calculated itself and saved in the database but I am getting this error in the postman.
Error: price() missing 1 required positional argument: 'self
My models:
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
ordered_date = models.DateTimeField(auto_now_add=True)
ordered = models.BooleanField(default=False)
total_price = models.CharField(max_length=50,blank=True,null=True)
#billing_details = models.OneToOneField('BillingDetails',on_delete=models.CASCADE,null=True,blank=True,related_name="order")
def __str__(self):
return self.user.email
def price(self):
total_item_price = self.quantity * self.item.varaints.price
return total_item_price
class OrderItem(models.Model):
#user = models.ForeignKey(User,on_delete=models.CASCADE, blank=True
#orderItem_ID = models.UUIDField(max_length=12, editable=False,default=str(uuid.uuid4()))
orderItem_ID = models.CharField(max_length=12, editable=False, default=id_generator)
order = models.ForeignKey(Order,on_delete=models.CASCADE, blank=True,null=True,related_name='order_items')
item = models.ForeignKey(Product, on_delete=models.CASCADE,blank=True, null=True)
order_variants = models.ForeignKey(Variants, on_delete=models.CASCADE,blank=True,null=True)
quantity = models.IntegerField(default=1)
total_item_price = models.PositiveIntegerField(blank=True,null=True,default=price())
ORDER_STATUS = (
('To_Ship', 'To Ship',),
('Shipped', 'Shipped',),
('Delivered', 'Delivered',),
('Cancelled', 'Cancelled',),
)
order_item_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')
Here quantity field is present in the OrderItem model itself but the price is present in the Variant model which is related to the Product model like this.
Things I tried:
I tried removing brackets () in price, but got same error.
If I tried putting price function inside class model before total_itel_price field, it says self is required inside bracket of price, and if I put self, = is required and I dont know to put in price(self=??)
Other Models:
Class Variants(models.Model):
...#other fields
price = models.DecimalField(decimal_places=2, max_digits=20,default=500)
Class Product(models.Model):
...#other fields
variants = models.ManyToManyField(Variants,related_name='products')
My serializer:
class OrderSerializer(serializers.ModelSerializer):
billing_details = BillingDetailsSerializer()
order_items = OrderItemSerializer(many=True)
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
class Meta:
model = Order
fields = ['id','user','ordered_date','order_status', 'ordered', 'order_items', 'total_price','billing_details']
# depth = 1
def create(self, validated_data):
user = self.context['request'].user
if not user.is_seller:
order_items = validated_data.pop('order_items')
billing_details = validated_data.pop('billing_details')
order = Order.objects.create(user=user,**validated_data)
BillingDetails.objects.create(user=user,order=order,**billing_details)
for order_items in order_items:
OrderItem.objects.create(order=order,**order_items)
else:
raise serializers.ValidationError("This is not a customer account.Please login as customer.")
Updated Code:
class OrderItem(models.Model):
#total_item_price = models.PositiveIntegerField(blank=True,null=True,default=0) #commented out this field other fields are same as above
order_item_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')
#property
def price(self):
return self.quantity * self.item.varaints.price
class OrderItemSerializer(serializers.ModelSerializer):
order = serializers.PrimaryKeyRelatedField(read_only=True)
price = serializers.ReadOnlyField()
class Meta:
model = OrderItem
fields = ['id','order','orderItem_ID','item','order_variants', 'quantity','order_item_status','price']
# depth = 1
Order Serializer is just like above. It includes OrderItemSerializer as shown:
class OrderSerializer(serializers.ModelSerializer):
billing_details = BillingDetailsSerializer()
order_items = OrderItemSerializer(many=True)
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
class Meta:
model = Order
fields = ['id','user','ordered_date','order_status', 'ordered', 'order_items', 'total_price','billing_details']
Update for Order total_price calculation.
This is what I did for total_price calculation but I am not getting total_price field in the api response, there is no error though.
class Order(models.Model):
.....#same fields as above
#property
def total_order_price(self):
return sum([_.price for _ in self.order_items_set.all()])
I have used price function in the OrderItem model and my instance of OrderItem is order_items. What is the issue??
Try this
class Order(models.Model):
"""Stores the details of the order"""
user: User = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
ordered_date = models.DateTimeField(auto_now_add=True)
ordered = models.BooleanField(default=False)
# billing_details = models.OneToOneField('BillingDetails',on_delete=models.CASCADE,null=True,blank=True,related_name="order")
def __str__(self) -> str:
return self.user.email
#property
def total_price(self) -> int:
"""
Dropped the total price field and created it as property
This is not the best practice, I am leaving that as practice for you :)
"""
return sum([_.total_item_price for _ in self.orderitem_set.all()])
class OrderItem(models.Model):
"""Order Item stores the details of the each order item"""
orderItem_ID: str = models.CharField(
max_length=12, editable=False, default=id_generator
)
order: Order = models.ForeignKey(
Order,
on_delete=models.CASCADE,
blank=True,
null=True,
related_name="order_items",
)
item: Product = models.ForeignKey(
Product, on_delete=models.CASCADE, blank=True, null=True
)
order_variants: Variants = models.ForeignKey(
Variants, on_delete=models.CASCADE, blank=True, null=True
)
quantity: int = models.IntegerField(default=1)
price = models.PositiveIntegerField()
#property
def total_item_price(self):
"""
Calculates total item price for the item
Here you can also add additional logics such as
taxes per item etc
"""
return self.price * self.quantity
ORDER_STATUS = (
("To_Ship", "To Ship"),
("Shipped", "Shipped"),
("Delivered", "Delivered"),
("Cancelled", "Cancelled"),
)
order_item_status = models.CharField(
max_length=50, choices=ORDER_STATUS, default="To_Ship"
)
This code finally worked for OrderItem price calculation:
class OrderItem(models.Model):
.....#fields same as above
#total_item_price = models.PositiveIntegerField(blank=True,null=True,default=0)
ORDER_STATUS = (
('To_Ship', 'To Ship',),
('Shipped', 'Shipped',),
('Delivered', 'Delivered',),
('Cancelled', 'Cancelled',),
)
order_item_status = models.CharField(max_length=50,choices=ORDER_STATUS,default='To_Ship')
#property
def price(self):
total_item_price = self.quantity * self.order_variants.price
return total_item_price
There was a typo in variants. Also, I should be using order_variants instead of item.variants because item has many variants but the user selects only one which has a unique price.
I have the code which calculates the sum just fine, now my question is it possible to multiple each price by quantity and then get the total sum after that in a cart on my website. I have tried with all of my logic but i have failed. The idea is to get the price of an item added to cart and multiply it by quantity and then get the total.
Here is my cart mode. models.py:
#cart model
class Cart(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
number_of_items = models.IntegerField(default=0)
user = models.ForeignKey(User, on_delete=models.CASCADE)
added_datetime = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.item.name
#Item model
class Item(models.Model):
CONDITION = (
('new', 'new'),
('used', 'used'),
('not applicable', 'not applicable'),
)
name = models.CharField(max_length=250)
owner = models.CharField(max_length=250, default='Ludocs-emark')
category = models.ForeignKey(ItemCategories, on_delete=models.CASCADE)
sub_category = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
Condition = models.CharField(max_length=250, null=True, choices=CONDITION)
price= models.IntegerField(default=0)
number_of_items = models.IntegerField(blank=True)
specification_one = models.CharField(max_length=250, blank=True)
specification_two = models.CharField(max_length=250, blank=True)
specification_three = models.CharField(max_length=250, blank=True)
specification_four = models.CharField(max_length=250, blank=True)
specification_five = models.CharField(max_length=250, blank=True)
specification_six = models.CharField(max_length=250, blank=True)
available_colors = models.CharField(max_length=250, blank=True)
description = RichTextField()
thumbnail = models.ImageField(default='default.png', upload_to='images/')
image_one = models.ImageField(upload_to='images/')
image_two = models.ImageField(upload_to='images/')
image_three = models.ImageField(upload_to='images/')
image_four = models.ImageField(upload_to='images/')
added_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
views.py file that i used to calculate the sum:
#This is the file where that i want to use to get the items added in cart and then multiply each by it's quantity and then get the total of the calculations when multiplied.
cart_sum = Cart.objects.filter(user=request.user).aggregate(Sum('item__price')).get('item__price__sum')
Yes, You can do that.
Try this
cart_sum = Cart.objects.filter(user=request.user).aggregate(Sum('item__price', field='item__price * number_of_items')).get('item__price__sum')
Assuming number_of_items as the quantity for the item from the Cart model.
Also you can return a total value so that if this gives any error for two different fields then you can do this
cart_sum = Cart.objects.filter(user=request.user).aggregate(total_price=Sum('item__price', field='item__price * number_of_items')).get('total_price')
I have a model CartItem that has a ForeignKey to a Product model.
Because from Product model I get the description, image, etc.
However, I want to have a method called sub_total that returns and integer. I use this to calculate total to be paid for this CartItem.
This sub_total method query a different model costo_de_los_productos using some of the properties of CartItem. like: self.product.category.name, self.product.name, self.size, self.quantity.
I need to return an Integer from sub_total method.
However, something is not right with me query, if I comment it and return 0 it works, but total is 0.
def sub_total(self):
product_price = costo_de_los_productos.objects.filter(category=self.product.category.name,
product = self.product.name,
size=self.size,
quantity=self.quantity).values_list("price", flat=True)
What could be wrong?
class CartItem(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
size = models.CharField(max_length=20, choices=TAMANIOS)
quantity = models.CharField(max_length=20, choices=CANTIDADES)
file = models.FileField(upload_to='files', blank=True, null=True)
comment = models.CharField(max_length=100, blank=True, null=True, default='')
uploaded_at = models.DateTimeField(auto_now_add=True)
step_two_complete = models.BooleanField(default=False)
# def __str__(self):
# return str(self.id) + " - " + str(self.size) + " por " + str(self.quantity)
def sub_total(self):
product_price = costo_de_los_productos.objects.filter(category = self.product.category.name,
product = self.product.name,
size=self.size,
quantity=self.quantity).values_list("price", flat=True)
# print(type(product_price))
return product_price
costo_de_los_productos model:
class costo_de_los_productos(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
price = models.IntegerField(default=30)
size = models.CharField(max_length=20, choices=TAMANIOS)
quantity = models.CharField(max_length=20, choices=CANTIDADES)
product model:
class Product(models.Model):
name = models.CharField(max_length=250, unique=False)
slug = models.SlugField(max_length=250, unique=False)
description = models.TextField(blank=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
image = models.ImageField(upload_to='product', blank=True, null=True)
available = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('name',)
verbose_name = 'product'
verbose_name_plural = 'products'
def get_url(self):
return reverse('shop:ProdDetail', args=[self.category.slug, self.slug])
def __str__(self):
return '{}'.format(self.name)
category model:
class Category(models.Model):
name = models.CharField(max_length=250, unique=True)
slug = models.SlugField(max_length=250, unique=True)
description = models.TextField(blank=True, null=True)
image = models.ImageField(upload_to='category', blank=True, null=True)
video = EmbedVideoField(null=True, blank=True)
class Meta:
ordering = ('name',)
verbose_name = 'category'
verbose_name_plural = 'categories'
def get_url(self):
return reverse('shop:allCat', args=[self.slug])
def __str__(self):
return '{}'.format(self.name)
Image of "costo_de_los_productos" from Admin Panel:
UPDATE 1
Cannot print anything after the product_price query.
def sub_total(self):
print("Enters Subtotal")
print(self.product.category.name)
print(self.product.name)
print(self.size)
print(self.quantity)
product_price = costo_de_los_productos.objects.filter(category=self.product.category.name,
product=self.product.name,
size=self.size,
quantity=self.quantity).values_list("price", flat=True)[0]
print("Line after product_price query")
print(type(product_price))
return product_price
Hard coding the values doesn't return expected integer:
def sub_total(self):
print("Enters Subtotal")
print(self.product.category.name)
print(self.product.name)
print(self.size)
print(self.quantity)
product_price = costo_de_los_productos.objects.filter(category="Stickers",
product="Stickers transparentes",
size="5cm x 5cm",
quantity=300).values_list("price", flat=True)[0]
print("Line after product_price query")
print(type(product_price))
return product_price
prints results:
Enters Subtotal
Stickers
Stickers transparentes
5cm x 5cm
300
How do I calculate the total with the existing model fields
class Book(models.Model):
school_id = models.ForeignKey(School)
name = models.CharField(max_length=100, default=None, blank=None,
unique=True)
class_name = models.CharField(max_length=50)
category = models.ForeignKey(Category)
bundle = models.CharField(max_length=20, unique=True)
particulars = models.CharField(max_length=50)
tax_code = models.CharField(max_length=50, default=None)
amount = models.FloatField()
tax_CGST = models.FloatField(default=0)
tax_SGST = models.FloatField(default=0)
total = models.FloatField()
def total(self):
return ((self.tax_SGST+self.tax_CGST)*self.amount)/100
def __str__(self):
return self.name
In the above code, I want the total function to calculate the total from the Tax and amount fields and add it to the total field in the database