Total Price Django - django

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 )

Just aggregate the total of ModelField total of the queryset like so
Total = Cart.objects.all().aggregate('total')
# Filtered in your case
Total = Cart.objects.filter(order_user=request.user).aggregate('total')
Apply filtering as necessary.
Also I suggest to have a good read here

You can retrieve the cart information for current users via the OrderItem model itself.
Check how annotate works
from django.db.models import Count
order_items = (OrderItem.objects.filter(cart__order_user=request.user)
.annotate(total=Count("quantity")*(item__price) + cart__total)
)

Related

How can I get a total price column for CartItem model?

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!
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']
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()
))

django related question querying list of won items by getting list of items then max bid from bid table for each item then check if user won it

I have a question here, I have two tables in my django models one for listings and one for bids
class Listing(models.Model):
class Meta:
verbose_name_plural = 'Listing'
title = models.CharField(max_length=64)
description = models.TextField()
price = models.DecimalField(max_digits=5, decimal_places=2)
image = models.URLField(max_length=500, default='')
category = models.CharField(max_length=32)
created = models.CharField(max_length=32)
addedon = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.title
class Bid(models.Model):
class Meta:
verbose_name_plural = 'Bid'
user = models.ForeignKey(User, on_delete=models.CASCADE)
item = models.ForeignKey(Listing, on_delete=models.CASCADE)
bid = models.DecimalField(max_digits=5, decimal_places=2)
created = models.DateTimeField(auto_now_add=True)
what i want is to show a page with all the user won items
def won(request):
listing = Listing.objects.filter(active=False)
the question here how i can make list of all then check max bid of each listing, then check is the current user is the winner and display it in the template won.html
like :
getMaxBid = Bid.objects.filter(item_id=listing.id).aggregate(Max('bid'))
maxBid = getMaxBid['bid__max']
then if the user is the winner display it
return render(request, "auctions/won.html", {
'listing': listing, 'active': False
})
thanks in advance
You can filter the Listing by first creating a Subquery expression [Django-doc] that will obtain the winner, and then check if the logged in user (or another user) is the winner, so:
from django.db.models import OuterRef, Subquery
listing = Listing.objects.alias(
bid_winner=Subquery(
Bid.objects.filter(item=OuterRef('pk')).order_by('-bid').values('user')
)[:1]
).filter(
active=False,
bid_winner=request.user
)
or Listings where the user has an active bid:
Listing.objects.filter(
bid__user=request.user,
active=True
).distinct()

django_filters, how do I query based on associated model?

My problem is like so,
I am using django-tables2 and I want to list some people on my page but these people should go through some queries. These queries will change according to information from other models.if the query is ok, this person will be in my table.
# My models
class AgeGroup(models.Model):
age_group = models.CharField(choices=age_choices, max_length=5)
class SolvedExam(models.Model):
age = models.ForeignKey(AgeGroup, on_delete=models.CASCADE, related_name='solved_exam_age_group')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='solved_exam')
class Person(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='person')
age = models.ForeignKey(AgeGroup, on_delete=models.CASCADE, related_name='person_age_group')
*
*
*
class Exam(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='person')
age = models.ForeignKey(AgeGroup, on_delete=models.CASCADE, related_name='exam_age_group')
*
*
*
# my view
class PersonList(SingleTableMixin, FilterView):
table_class = PersonTable
model = Person
queryset = Person.objects.all()
paginate_by = 10
template_name = 'person/person-list.html'
filterset_class = PersonFilter
def get_queryset(self):
super(Ogrenciler, self).get_queryset()
return Person.objects.filter( **some query** )
raise Http404
I want to list the students if there are exams which is not finished in the person's age group. Thank you very much!
Where is the information about the examns, and the examns that where not passed? Typically I would expect an fields like Exman_id, class name, boolean passed etc.

how to fetch data from many to many field objects?

I am getting stuck in many to many field objects in my model i want to retrieve the price of product from the order model objects but while fetching it gives sometime many related manager error or query set error
models.py
from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User
class Product(models.Model):
name = models.CharField(max_length=100, db_index=True)
slug = models.SlugField(max_length=100, db_index=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
available = models.BooleanField(default=True)
stock = models.PositiveIntegerField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Order(models.Model):
user = models.ForeignKey(User,on_delete= models.SET_NULL,null = True)
product = models.ManyToManyField('Order.Product')
is_ordered = models.BooleanField(default =False)
date_ordered = models.DateTimeField(auto_now = True,null = True)
views.py
def get_product_price(request):
if request.method=="GET":
user=User.objects.get(username = "hemant")
orders = user.order_set.all()
order = orders[0]
price = order.product.price
return HttpResponse(price)
When you are getting value from ManyToManyField, you need to do it like this:
products = order.product.all()
If you want to get the prices, you can do it like this:
products = order.product.all()
for product in products:
print(product.price)
If you want to return prices as a http response, then you can use values_list() to get list of prices from queryset. Like this
import json
views.py
def get_product_price(request):
if request.method=="GET":
user=User.objects.get(username = "hemant")
orders = user.order_set.all()
order = orders[0]
price = list(order.product.all().values_list('price', flat=True))
return HttpResponse(json.dumps(price))

View and Template for m2m with Through

In my app i need to store invoices (Invoice) of known products (Product) to calculate points for each seller (User). I'm trying to create form to insert basic invoice data plus inline form with sold products info. To handle it i create model like this:
class Product(models.Model):
group = models.CharField(max_length = 200, blank = False)
mark = models.CharField(max_length = 200, blank = True)
points = models.IntegerField(blank = False)
class Invoice(models.Model):
price = models.FloatField(blank=False)
file = models.FileField(blank=False)
product = models.ManyToManyField(Product, through='Sold')
user = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateField()
date_created = models.DateField(auto_now_add=True)
date_updated = models.DateField(auto_now=True)
class Sold(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
I tried to manage it via django-admin and it work fine with admin.py:
class ProductTabular(admin.TabularInline):
model = Invoice.product.through
class InvoiceAdmin(admin.ModelAdmin):
inlines = [ProductTabular]
exclude = ('product', )
class Meta:
model = Invoice
admin.site.register(Invoice, InvoiceAdmin)
but i'm unable to create such form in own templates. Please, can you help me with views.py and template to get same result as for the django-admin?
I tried via invoce form with inlineformset_factory for the Sold model, but i can't figure out how to save it. Thanks for any help!