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']
Related
I have to serialize spare instance from spare variety many to many field.
Models.py
class SpareVariety(models.Model):
quality = models.ForeignKey(Quality, max_length=255, on_delete=models.CASCADE, null=True, blank=True)
variety_name = models.CharField(max_length=255, null=True, blank=True)
property = models.ForeignKey(SpareProperty, null=True, blank=True, on_delete=models.CASCADE)
purchase_price = models.PositiveIntegerField(help_text="in INR", blank=True, null=True)
retail_price = models.FloatField(help_text="All values in INR", blank=True, null=True)
dealer_price = models.FloatField(help_text="All values in INR", blank=True, null=True)
stock_available = models.PositiveIntegerField(blank=True, null=True,default=True)
spare_costing = models.ForeignKey(SpareCosting, on_delete=models.CASCADE, blank=True, null=True)
spare_discount = models.ForeignKey(Discount, on_delete=models.CASCADE, blank=True, null=True)
is_available = models.BooleanField(default=False)
date_added = models.DateTimeField(auto_now=True)
date_updated = models.DateTimeField(auto_now_add=True)
class Spare(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
spare_variety = models.ManyToManyField(SpareVariety, related_name='spare_varieties', null=True, blank=True)
name = models.CharField(max_length=255, help_text="Enter the name of spare (Ex:Display, Speakers)")
type = models.ForeignKey(Type, blank=True, null=True, on_delete=models.CASCADE)
date_added = models.DateTimeField(auto_now=True)
date_updated = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.product.name, self.name)
Serialize the spare model from spare variety serializer
serializers.py
class SpareVarietySerializer(serializers.HyperlinkedModelSerializer):
spare_costing= SpareCostingSerializer(many=False, read_only=False)
spare_discount = DiscountSerializer(many=False, read_only=False)
quality = QualitySerializer(many=False, read_only=False)
property = SparePropertySerializer(many=False, read_only=False)
spare_name = serializers.CharField(read_only=True, source="spare.name")
class Meta:
model = SpareVariety
fields = ['id','quality','variety_name','purchase_price','spare_name','retail_price','property', 'dealer_price', 'stock_available','spare_costing','spare_discount','is_available', 'date_added', 'date_updated',]
I can't open my Review table, here's the models of code:
This is the `Project` model:
class Project(models.Model):
title = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
demo_link = models.CharField(max_length=2000, null=True, blank=True)
source_link = models.CharField(max_length=2000, null=True, blank=True)
tags = models.ManyToManyField('Tag', blank=True)
vote_total = models.IntegerField(default=0, null=True, blank=True)
vote_ratio = models.IntegerField(default=0, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True,
primary_key=True, editable=False)
def __str__(self):
return self.title
And this is the Review model:
class Review(models.Model):
VOTE_TYPE = (
('up', 'Up Vote'),
('down', 'Down Vote'),
)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
body = models.TextField(null=True, blank=True)
value = models.CharField(max_length=200, choices=VOTE_TYPE)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True,primary_key=True, editable=False)
def __str__(self):
return self.title
but I can't open my Review table on admin panel (OperationalError at /admin/projects/review/)
Here's the error details:
I make migrations and do migrate:
how do I make it better for the website operator to process the order, can we have each orderitem and shippingaddress associated with the order to be under each "Order" in the admin panel? for example when someone clicks on an Order, he sees the Order data and he's able to scroll and also see the orderitem, and shipping address, would really appreciate your help, thx!
models.py
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, blank=True, null=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, blank=True, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, blank=True, null=True)
quantity = models.IntegerField(default=0)
date_added = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=40, choices=STATUS_CHOICES, default="Order Placed")
tracking_no = models.CharField(max_length=300, null=True, blank=True)
class ShippingAddress(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, blank=True, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, blank=True, null=True)
address_one = models.CharField(max_length=200)
city = models.CharField(max_length=200)
country = models.CharField(max_length=300)
zipcode = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
what it looks like rn:
admin.py
admin.site.register(Order, OrderAdmin)
admin.site.register(OrderItem, OrderItemAdmin)
admin.site.register(ShippingAddress, ShippingAddressAdmin)
This would be a solution which works for you
class OrderItemAdmin(admin.StackedInline):
model = OrderItem
class ShippingAddressAdmin(admin.StackedInline):
model = ShippingAddress
class OrderAdmin(admin.ModelAdmin):
inlines = [OrderItemAdmin, ShippingAddressAdmin]
admin.site.register(Order, OrderAdmin)
This is well documented here: https://docs.djangoproject.com/en/stable/ref/contrib/admin/#inlinemodeladmin-objects
I have a problem in obtaining a single id from a queryset. I post my models and views in order to be more clear:
models.py
class MissionEntry(models.Model):
student = models.ForeignKey(
Student, on_delete=models.DO_NOTHING, blank=True, null=True)
mission = models.ForeignKey(
Mission, on_delete=models.DO_NOTHING, null=True, blank=True)
log_entry = models.ForeignKey(
LogEntry, on_delete=models.DO_NOTHING, blank=True, null=True)
learning_objective = models.ForeignKey(
LearningObjective, on_delete=models.DO_NOTHING, blank=True, null=True)
grade = models.CharField(
max_length=10, choices=GRADING_VALUE, blank=True, null=True)
note = models.TextField(blank=True, null=True)
debriefing = models.TextField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.mission) + ' ' + str(self.log_entry)
class Meta:
verbose_name_plural = 'Mission Entries'
class MissionEntryStatus(models.Model):
mission = models.ForeignKey(
Mission, on_delete=models.PROTECT, null=True, blank=True)
student = models.ForeignKey(Student, on_delete=models.PROTECT)
is_completed = models.BooleanField(default=False)
is_failed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class StudentMission(models.Model):
mission = models.ForeignKey(Mission, on_delete=models.PROTECT)
student_training_course = models.ForeignKey(
StudentTrainingCourse, on_delete=models.PROTECT)
mission_status = models.ForeignKey(
MissionEntryStatus, on_delete=models.PROTECT, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['mission__name']
def __str__(self):
return self.mission.name
class LogEntry(models.Model):
aircraft = models.ForeignKey(Aircraft, on_delete=models.DO_NOTHING)
adep = models.ForeignKey(
Aerodrome, on_delete=models.PROTECT, related_name='adep')
ades = models.ForeignKey(
Aerodrome, on_delete=models.PROTECT, related_name='ades')
date = models.DateField()
etd = models.TimeField()
ata = models.TimeField()
eet = models.TimeField()
function_type = models.ForeignKey(FunctionType, on_delete=models.PROTECT)
student = models.ForeignKey(
Student, on_delete=models.PROTECT, blank=True, null=True)
instructor = models.ForeignKey(
Instructor, on_delete=models.PROTECT, blank=True, null=True)
student_mission = models.ForeignKey(
'mission.StudentMission', on_delete=models.PROTECT, null=True, blank=True)
note = models.TextField(null=True, blank=True)
cross_country = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
views.py
def student_mission_list(request, pk):
student = Student.objects.get(id=pk)
student_training_course = StudentTrainingCourse.objects.filter(
student_id=student.id)
missions = StudentMission.objects.filter(
student_training_course_id__in=student_training_course)
mission_entry = MissionEntry.objects.filter(student_id=student)
log_entry = LogEntry.objects.filter(student_mission_id__in=missions)
print(log_entry)
context = {
'student': student,
'missions': missions,
'mission_entry': mission_entry,
}
return render(request, 'mission/student_mission_list.html', context)
In fact, what I need to do, is to obtain a single value for the log_entry. The problem is that, obviously, I am retrieving multiple values of log_entry. But I would like to get the single pk of the log_entry.
Any suggestion? Should I remodel the models.py file?
try this:
log_entry = LogEntry.objects.get(student_mission_id__in=missions)
print(log_entry.id)
I am designing django models for a E-commerce market place site where user can buy 4 type of products . Like I have 4 type of diff models for them .
For clothes
class Merchandise(models.Model):
adOwner = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
imagesMerchandise = models.ManyToManyField(merchandiseImages)
productName = models.CharField(max_length=50, null=False, blank=False)
price = models.IntegerField()
availableQuality=models.IntegerField()
color=models.CharField(max_length=20, null=False, blank=False)
size = models.CharField(max_length=50 , null=False , blank=False)
description=models.CharField(max_length=250 , null=False , blank=False)
is_approved = models.BooleanField(default=False)
def __str__(self):
return str(self.productName)
for Rent a Car
class Vehicle(models.Model):
adOwner=models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
carImages=models.ManyToManyField(Image)
make=models.CharField(max_length=50, null=False, blank=False)
modelName=models.CharField(max_length=50, null=False, blank=False)
registrationNumber=models.CharField(max_length=50, null=False, blank=False)
modelYear=models.CharField(max_length=50, null=False, blank=False)
modelColor=models.CharField(max_length=50, null=False, blank=False)
carType=models.CharField(max_length=50, null=False, blank=False)
fuelMileage=models.CharField(max_length=50, null=False, blank=False)
SeatingCapacity=models.CharField(max_length=50, null=False, blank=False)
vehicleCondition=models.CharField(max_length=50, null=False, blank=False)
fuelType=models.CharField(max_length=50, null=False, blank=False)
price=models.CharField(max_length=50, null=False, blank=False)
description=models.CharField(max_length=500, null=True, blank=True)
registerIn=models.CharField(max_length=500, null=True, blank=True)
is_approved = models.BooleanField(default=False)
def __str__(self):
return str(self.modelName)
book a hotel
class Accommodation(models.Model):
adOwner = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
hotleImages = models.ManyToManyField(HotleImages)
accommodationTitle=models.CharField(max_length=150)
location = models.CharField(max_length=150)
accommodationName = models.CharField(max_length=150)
checkIn = models.TimeField()
checkOut = models.TimeField()
# accessibility = models.CharField(max_length=20, null=False, blank=False)
address = models.CharField(max_length=150)
pets = models.CharField(max_length=150)
child = models.CharField(max_length=150)
is_approved = models.BooleanField(default=False)
Create a Activity
class ActivityOrganizer(models.Model):
adOwner = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
activityImage = models.ManyToManyField(ActivityImage)
activityName = models.CharField(max_length=50 , null=False, blank=False)
activityId = models.CharField(max_length=20, null=False, blank=False)
ageSuggestion = models.CharField(max_length=20, null=True, blank=True)
duration = models.CharField(max_length=20, null=False, blank=False)
openTime = models.TimeField()
closeTime=models.TimeField()
expiryDate = models.DateField()
availableQty = models.IntegerField()
price = models.IntegerField()
needToBring = models.CharField(max_length=50 , null=True , blank=True)
personsAllowOnOneTicket = models.IntegerField()
location = models.CharField(max_length=50 , null=True , blank=False)
specialNotes = models.CharField(max_length=250 ,null=True , blank=True)
description = models.CharField(max_length=250 , null=True , blank=True)
is_approved = models.BooleanField(default=False)
Now I made a order Table like this
class Orders(models.Model):
order_number = models.AutoField(primary_key=True)
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
ordertime = models.DateTimeField(auto_now_add=True)
user_note=models.CharField(max_length=150 , null=True, blank=True)
address=models.CharField(max_length=150 , null=True, blank=True)
order_status = models.CharField(choices=STATUS , max_length=50)
payment_status=models.BooleanField(default=0)
Now I am confuse how to bind all these 4 categories to my order object. as If its a for single category I can simply create a foreign key with order model. But How can I bind all these (as user can pick 1,2,3,4 number of categories ) so if user select Accommodation , and Vehicle categories products how I can save 2 categories null in foreign key. Any help would be highly appreciated . thanks
If you have small number of products (4 in your case) and for each order only one item of a type can be ordered, then you can simply add those to the Orders model with nullable fields
class Orders(models.Model):
order_number = models.AutoField(primary_key=True)
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
ordertime = models.DateTimeField(auto_now_add=True)
user_note=models.CharField(max_length=150 , null=True, blank=True)
address=models.CharField(max_length=150 , null=True, blank=True)
order_status = models.CharField(choices=STATUS , max_length=50)
payment_status=models.BooleanField(default=0)
merchandise = models.ForeignKey(Merchandise, on_delete=models.CASCADE, null=True, blank=True)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE, null=True, blank=True)
accommodation = models.ForeignKey(Accommodation, on_delete=models.CASCADE, null=True, blank=True)
activity_organizer = models.ForeignKey(ActivityOrganizer, on_delete=models.CASCADE, null=True, blank=True)
To list all the orders of a specific category, exclude all the orders with null in given field.
Orders.objects.exclude(merchandise__isnull=True)
Also if only a single category product is ordered rest 3 fields will be null, if you want to enforce that business logic then you can check for it by creating a signal.