Reputation: 2217
I have two models in Django.
One for the products and another is for ratings.
Product Model:
class Product(models.Model):
...
product_name = models.CharField(max_length=264, blank=False, verbose_name='Product Name')
product_slug = models.SlugField(blank=True)
avg_rating = models.IntegerField(blank=True, null=True, verbose_name='Average Rating', help_text='Do not Edit!')
total_rating_count = models.IntegerField(blank=True, null=True, verbose_name='Total Rating', help_text='Do not Edit!')
def save(self, *args, **kwargs):
...
super(Product, self).save(*args, **kwargs)
def __str__(self):
return self.product_name
Rating Model:
class Rating(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='product_ratings')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_rating')
product_rating = models.IntegerField(verbose_name='Rating', blank=False)
product_comment = models.TextField(verbose_name='Comment', blank=False)
What I want to do is that when a user rates a product, I want to update the avg_rating
and total_rating_count
in the Product model.
How can I do that? Thank you.
Upvotes: 0
Views: 48
Reputation: 744
To echo what Willem has said, I would remove those fields and calculate them like this:
from django.db.models import Avg
class Product(models.Model):
...
product_name = models.CharField(max_length=264, blank=False, verbose_name='Product Name')
product_slug = models.SlugField(blank=True)
@property
def avg_rating(self):
return self.product_ratings.all().aggregate(Avg('product_rating'))['product_rating__avg']
@property
def total_rating_count(self):
return self.product_ratings.all().count()
You can then access this information like any other attribute:
product = Product.objects.first()
product.avg_rating
I would consider using a cached_property for performance considerations.
Upvotes: 2