Home > Back-end >  Rendering average rating on a single product - probably an easy solve, but cannot find the problem
Rendering average rating on a single product - probably an easy solve, but cannot find the problem

Time:07-25

I am trying to show display the average rating for a given single product from every ratings made by users on this single product.

Which I managed to do. However my code seems to render all products and relating reviews and not just the specific product.

Clearly, I am telling the code, somewhere, to render all products instead of one. But I am not too sure where. I think it's coming form the code in my views.py.

Something to specify also, in the same page, I am trying to display:

  1. Average review per product (that's what I am working on)
  2. All reviews from different user on the specific product (that works)

Is it 2. that creates a problem? Should I also make a reference to the product_id in the second line of the views too? (if so, where?)

Models

class Product(models.Model):
    name = models.CharField('Product Name', max_length=120, null=True)
    class Meta:
        db_table='Product'
    def __str__(self):
        return str(self.name)

class ReviewRating(models.Model):
    user = models.ForeignKey(User,blank=True,on_delete=models.CASCADE)
    product=models.ForeignKey(Product,related_name="comments", on_delete=models.CASCADE)
    rating_1 = models.IntegerField(choices=RATING1,default=0)    
    def __str__(self):
        return '%s - %s - %s'%(self.user, self.product, self.date_added)

Views

from django.db.models import Avg
 
def Notes (request, product_id):
    product = Product.objects.get(pk=product_id)
    data = Product.objects.order_by('name').annotate(
        avg_rating_1 =Avg('comments__rating_1 '),

    return render(request, 'main/notes.html',{'product':product, 'data':data})

Template

{% for ReviewRating in data%}

{{ReviewRating.avg_rating_1 }}

{% endfor %}

CodePudding user response:

Hello you should use aggregation and @property decorator to use this method as a field inside you project. Here example to your code.

class Product(models.Model):
    name = models.CharField('Product Name', max_length=120, null=True)

    class Meta:
        db_table='Product'

    def __str__(self):
        return str(self.name)
    
    @property
    def rating(self):
        rating = self.comments.aggregate(Avg('rating_1'))['rating_1__avg']

And inside your template you can use this like this:

{% for ReviewRating in champagnes %}

{{ReviewRating.rating_1 }}

{% endfor %}

Do not forget to import Avg from django.db.models import Avg

CodePudding user response:

Solved.

All I needed to change the views from "order_by" to "filter(pk=product_id)".

I knew that was simple! (thanks for those who tried to help)

from django.db.models import Avg
 
def Notes (request, product_id):
    product = Product.objects.get(pk=product_id)
    data = Product.objects.filter(pk=product_id).annotate(
        avg_rating_1 =Avg('comments__rating_1 '),

    return render(request, 'main/notes.html',{'product':product, 'data':data})
  • Related