I need to get the user who placed the highest bid for the listing on an auction site.
models.py:
class Listing(models.Model):
class Category(models.TextChoices):
BOOKS = 'Books'
SPORTS = 'Sports'
DEATHLY_HALLOWS = 'Deathly Hallows'
CLOTHING = 'Clothing'
WANDS = 'Wands'
JEWELRY = 'Jewelry'
title = models.CharField(max_length=64)
description = models.TextField(max_length=320)
starting_bid = models.DecimalField(max_digits=10, decimal_places=2, default=0)
current_price = models.DecimalField(max_digits=10, decimal_places=2, default=0 )
img_url = models.URLField(blank=True)
category = models.CharField(choices=Category.choices, max_length=64, blank=True)
is_closed = models.BooleanField(default=False)
user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
winner = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name="Winner")
def __str__(self):
return f"{self.title}"
class Bid(models.Model):
listing = models.ForeignKey(Listing, on_delete=models.CASCADE, default=1)
bid = models.DecimalField(max_digits=10, decimal_places=2)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name="Bidder")
views.py:
def listing(request, listing_id):
highest_bid = Bid.objects.aggregate(Max('bid'))
winner = highest_bid.user
print(winner)
Returns the error: 'dict' object has no attribute 'user'.
How can I get the user from the maximum bid placed on the listing?
Order the Bids by the bid:
def listing(request, listing_id):
highest_bid = Bid.objects.latest('bid')
winner = highest_bid.user
print(winner)
# …
Related
I am working on a project where everything works out aside some litle part of code which has to return the total price of items in the cart, but it only returns the price of the first item in the cart.
Here is the code, it doesn't add all the price in the loop.
models.py
class Item (models.Model):
title = models.CharField(max_length=100)
price = models.FloatField()
d_price = models.FloatField(blank=True, null=True)
tax = models.FloatField(blank=True, null=True)
category = models.CharField(choices=CATEGORY_CHOICES, max_length=2)
label = models.CharField(choices=LABEL_CHOICES, max_length=1)
slug = models.SlugField()
description = models.TextField()
crated = models.DateTimeField(auto_now_add=True)
photo = models.ImageField(upload_to='photos', null=False, blank=False)
image1 = models.ImageField(upload_to='photos', null=False, blank=False)
image2 = models.ImageField(upload_to='photos', null=False, blank=False)
image3 = models.ImageField(upload_to='photos', null=False, blank=False)
image4 = models.ImageField(upload_to='photos', null=False, blank=False)
def __str__(self):
return self.title
class OrderItem (models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
ordered = models.BooleanField(default=False)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
def __str__(self):
return f"{self.quantity} of {self.item.title}"
def total_price(self):
return self.quantity * self.item.price
def total_d_price(self):
return self.quantity * self.item.d_price
def saving(self):
return self.total_price() - self.total_d_price()
def get_total_price(self):
if self.item.d_price:
return self.total_d_price()
else:
return self.total_price()
class Order (models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
items = models.ManyToManyField(OrderItem)
start_date = models.DateTimeField(auto_now_add=True)
ordered_date = models.DateTimeField()
ordered = models.BooleanField(default=False)
def __str__(self):
return self.user.username
#property
def final_price(self):
total = 0
for order_item in self.items.all():
total += order_item.get_total_price()
return total
I am building an ecommerce website with django. In my models I have a Product and review model. How should i connect the two for the number of reviews and average rating attribute?
This is my current models file
class Product(models.Model):
name = models.CharField(max_length=200, null=True, blank=True)
brand = models.CharField(max_length=200, null=True, blank=True)
image = models.ImageField(null=True, blank=True, default='placeholder.png')
description = models.TextField(null=True, blank=True)
rating = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
countInStock = models.IntegerField(null=True, blank=True, default=0)
id = models.UUIDField(default=uuid.uuid4, max_length=36, unique=True, primary_key=True, editable=False)
numReviews = [Count the number of reviews where product.id matches self.id]
averageRating = [Sum up the ratings in reviews for this product and divide them by their count]
def __str__(self):
return str(self.name)
class Review(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
rating = models.IntegerField(null=True, blank=True, default=0)
comment = models.TextField(null=True, blank=True)
createdAt = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, max_length=36, unique=True, primary_key=True, editable=False)
def __str__(self):
return f'{self.user} review for {self.product}'
As you can see the numReviews and average rating columns are meant to connect both tables. I have been trying to figure out how to do it correctly with no success.
Any help would be greatly appreciated
I would make them into model methods.. I don't think there will be any issues that the Review object is defined below the method
and for the Avg I used a Django command aggregate which forces the DB to do the work.
models.py
class Product(models.Model):
name = models.CharField(max_length=200, null=True, blank=True)
brand = models.CharField(max_length=200, null=True, blank=True)
image = models.ImageField(null=True, blank=True, default='placeholder.png')
description = models.TextField(null=True, blank=True)
rating = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
countInStock = models.IntegerField(null=True, blank=True, default=0)
id = models.UUIDField(default=uuid.uuid4, max_length=36, unique=True, primary_key=True, editable=False)
def __str__(self):
return str(self.name)
def num_of_reviews(self):
return Review.objects.filter(product=self).count()
def average_rating(self):
from django.db.models import Avg
return Review.objects.filter(product=self).aggregate(Avg('rating'))['rating__avg']
Use
obj = Product.objects.all().first()
obj.num_of_reviews()
obj.average_rating()
Edit
Reverse relationship per #NixonSparrow
def num_of_reviews(self):
return self.review_set.count()
def average_rating(self):
from django.db.models import Avg
return self.review_set.aggregate(Avg('rating'))['rating__avg']
I am trying to filter my many to many variation fields with respect to the product. means, I only want the variations related to the current product to show in the admin page. now its showing all the variations available for every product.
I added formfield_for_manytomany() function to my admin.py but how can I get the current product(id) in the cart or order to filter the variations?
most of the questions in stack overflow Is based on the current user, which is easy to get? but how should I get the specific product(id) that is opened in the admin panel.
admin.py
from django.contrib import admin
from .models import *
from products.models import Variation
class CartAdmin(admin.ModelAdmin):
list_display = ('cart_id', 'date_created')
class CartItemAdmin(admin.ModelAdmin):
list_display = ('user','cart', 'product', 'quantity','is_active')
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "variation":
product = Products.objects.get(id='??') # how I get the current product in the cart or order
kwargs["queryset"] = Variation.objects.filter(product=product.id)
return super().formfield_for_manytomany(db_field, request, **kwargs)
admin.site.register(Cart, CartAdmin)
admin.site.register(CartItem, CartItemAdmin)
CartItem Model
class CartItem(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True)
cart = models.ForeignKey(Cart, on_delete=models.CASCADE, null=True)
product = models.ForeignKey(Products, on_delete=models.CASCADE)
variation = models.ManyToManyField(Variation, blank=True)
quantity = models.IntegerField()
is_active = models.BooleanField(default=True)
created_date = models.DateTimeField(auto_now_add=True)
def item_total(self):
return self.product.price * self.quantity
def __str__(self):
return self.product.name
Product and Variation Model
class Products(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = AutoSlugField(populate_from='name', max_length=100, unique=True)
isbn = models.CharField(max_length=20, unique=True, blank=True, null=True)
sub_category = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
language = models.ForeignKey(Language, on_delete=models.SET_NULL, null=True)
author = models.CharField(max_length=100)
Publisher = models.CharField(max_length=100, blank=True, default=None)
release_date = models.DateField(blank=True, null=True, default=None)
price = models.IntegerField(default=None)
stock = models.IntegerField(default=None)
is_available = models.BooleanField(default=True)
cover_image = models.ImageField(upload_to='images/products')
image1 = models.ImageField(upload_to='images/products', blank=True, default=None, null=True)
image2 = models.ImageField(upload_to='images/products', blank=True, default=None, null=True)
image3 = models.ImageField(upload_to='images/products', blank=True, default=None, null=True)
description = models.TextField(max_length=2000, blank=True, default=None)
create_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
number_of_pages = models.IntegerField(blank=True, null=True)
weight = models.IntegerField(blank=True, null=True)
width = models.IntegerField(blank=True, null=True)
height = models.IntegerField(blank=True, null=True)
spine_width = models.IntegerField(blank=True, null=True)
class Meta:
verbose_name = 'Product'
verbose_name_plural = 'Products'
def get_url(self):
return reverse('product-view', args=[self.slug])
def __str__(self):
return self.name
class Variation(models.Model):
product = models.ForeignKey(Products, on_delete=models.CASCADE)
variation_category = models.CharField(max_length=100, choices=variation_category_choice)
variation_value = models.CharField(max_length=100, choices=variation_value_choice)
is_available = models.BooleanField(default=True)
date_added = models.DateTimeField(auto_now_add=True)
objects = VariationManager()
def __str__(self):
return self.variation_value
I have a method that creates orders from the user's cart. For the courier to take an order from different restaurants, the order is divided into several. But at the moment I'm splitting the order just by the dish in the cart. How to make an order split by restaurants? that is, if a user orders 5 dishes from two different restaurants, then 2 orders were formed.
views.py
#action(methods=['PUT'], detail=False, url_path='current_customer_cart/add_to_order')
def add_cart_to_order(self, *args, **kwargs):
cart = Cart.objects.get(owner=self.request.user.customer)
cart_meals = CartMeal.objects.filter(cart=cart)
data = self.request.data
for cart_meal in cart_meals:
order = Order.objects.create(customer=self.request.user.customer,
cart_meal=cart_meal,
first_name=data['first_name'],
last_name=data['last_name'],
phone=data['phone'],
address=data.get('address', self.request.user.customer.home_address),
restaurant_address=cart_meal.meal.restaurant.address,
)
order.save()
return response.Response({"detail": "Order is created", "added": True})
models.py
class Order(models.Model):
"""User's order"""
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='related_orders')
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
phone = models.CharField(max_length=20)
cart_meal = models.ForeignKey(CartMeal, on_delete=models.CASCADE, null=True, blank=True)
restaurant_address = models.CharField(max_length=1024, null=True)
address = models.CharField(max_length=1024)
status = models.CharField(max_length=100, choices=STATUS_CHOICES, default=STATUS_NEW)
created_at = models.DateTimeField(auto_now=True)
delivered_at = models.DateTimeField(null=True, blank=True)
courier = models.OneToOneField('Courier', on_delete=models.SET_NULL, null=True, blank=True)
class CartMeal(models.Model):
"""Cart Meal"""
user = models.ForeignKey('Customer', on_delete=models.CASCADE)
cart = models.ForeignKey('Cart', verbose_name='Cart', on_delete=models.CASCADE, related_name='related_meals')
meal = models.ForeignKey(Meal, verbose_name='Meal', on_delete=models.CASCADE)
qty = models.IntegerField(default=1)
final_price = models.DecimalField(max_digits=9, decimal_places=2)
class Meal(models.Model):
"""Meal"""
title = models.CharField(max_length=255)
description = models.TextField(default='The description will be later')
price = models.DecimalField(max_digits=9, decimal_places=2)
discount = models.IntegerField(default=0)
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE, null=True)
slug = models.SlugField(unique=True)
class Restaurant(models.Model):
"""Restaurant"""
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True)
address = models.CharField(max_length=1024)
owner = models.ForeignKey('Restaurateur', on_delete=models.CASCADE, null=True)
meals = models.ManyToManyField('Meal', related_name='related_restaurant', blank=True)
How can I do this, please help me
You can group your meals with respect to resturants.
import itertools
from core.models import CartMeal, Order
for restaurant, cart_meals in itertools.groupby(CartMeal.objects.order_by('meal__restaurant'), lambda s: s.meal.restaurant):
order = Order.objects.create(
customer=self.request.user.customer,
first_name=data['first_name'],
last_name=data['last_name'],
phone=data['phone'],
address=data.get('address', self.request.user.customer.home_address),
restaurant_address=cart_meal.meal.restaurant.address,
)
order.cart_meal.set([cart_meal for cart_meal in cart_meals])
Ref: The answer is formulated by taking help from following answer.
https://stackoverflow.com/a/57897654/14005534
I want to update a field which is called level. My relation is like this. i am using django User model. Which is extended to Extended user like this below:-
class ExtendedUser(models.Model):
levels_fields = (
("NEW SELLER", "NEW SELLER"),
("LEVEL1", "LEVEL1"),
("LEVEL 2", "LEVEL 2"),
("LEVEL 3", "LEVEL 3")
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
email = models.EmailField(null=True, unique=True)
contact_no = models.CharField(max_length=15, null=True)
profile_picture = models.ImageField(upload_to="images/", null=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE, null=True)
city = models.ForeignKey(City, on_delete=models.CASCADE, null=True)
level = models.CharField(max_length = 120, null=True, blank=True, choices=levels_fields, default="NEW SELLER")
I have a field call "Level" which is full of choices. Now i have a model named Checkout
This is the checkout model :-
class Checkout(models.Model):
ORDER_CHOICES = (
("ACTIVE", "ACTIVE"),
("LATE", "LATE"),
("DELIVERED", "DELIVERED"),
("CANCELLED", "CANCELLED"),
)
user = models.ForeignKey(User, on_delete=models.CASCADE)
seller = models.ForeignKey(
User, on_delete=models.CASCADE, null=True, related_name='seller')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
first_name = models.CharField(max_length=120)
last_name = models.CharField(max_length=120)
package = models.ForeignKey(OfferManager, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=0)
price = models.DecimalField(decimal_places=2, max_digits=10, default=0.00)
total = models.DecimalField(decimal_places=2, max_digits=10, default=0.00)
grand_total = models.DecimalField(
decimal_places=2, max_digits=10, default=0.00, null=True)
paid = models.BooleanField(default=False)
due_date = models.DateField(null=True)
order_status = models.CharField(max_length=200, choices=ORDER_CHOICES, default="ACTIVE")
is_complete = models.BooleanField(default=False, null=True)
I have another model which is called SellerSubmit and the checkout is the foreign key here. Here is the model :-
class SellerSubmit(models.Model):
checkout = models.ForeignKey(Checkout, on_delete=models.CASCADE, related_name="checkout")
file_field = models.FileField(upload_to="files/", null=True)
submit_date = models.DateField(auto_now_add=True, null=True)
def __str__(self):
return str(self.id)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
Now when a seller post in the SUbmitModel it will update the level to LEVEL1. How can do it,
This is what i tried :-
def sellerSubmitView(request, pk):
form = SellerSubmitForm()
if request.method == "POST":
file_field = request.FILES.get("file_field")
try:
checkout = Checkout.objects.get(id=pk)
# print(file_field)
except:
return redirect("manage-order")
else:
SellerSubmit.objects.create(checkout=checkout, file_field=file_field)
checkout.order_status ="DELIVERED"
chk = checkout.is_complete = True
l = Checkout.objects.filter(is_complete = True).filter(seller=request.user).count()
print("Count:" + str(l))
if l > 5:
out = checkout.seller.extendeduser.level = "LEVEL1"
print(out)
checkout.save()
print(chk)
checkout.save()
return redirect("manage-order")
args = {
"form": form,
"checkout_id": pk,
}
return render(request, "wasekPart/sellerSubmit.html", args)
checkout.seller.extendeduser.level = "LEVEL1"
checkout.seller.extendeduser.save()
This should solve your problem
out = checkout.seller.extendeduser.level = "LEVEL1"
print(out)
checkout.seller.extendeduser.save()
checkout.save()
It's my bad that didn't notice ExtendedUser is not extended from User.
Please let me know if it's worked or not