Destiny Franks
Destiny Franks

Reputation: 801

Django: how to count the ratings and reviews of a post using django?

i have a model course and i also have a model review and rating that allows users rate a particular course. now i want to count all the ratings on each course when i filter. NOTE: in the courses detail view i figured out a way to count the ratings like this rating_count = CourseRating.objects.filter(course=course, rating__in=["3.0", "4.0", "5.0"]).count(). This only worked in the detail view because i get the course first using course = Course.objects.get(slug=course_slug).

Now i want to count the rating in course lists view, how can i do this while using filter?

this is how the detail view looks like

@login_required
def course_details(request, course_slug):
    user = request.user
    course = Course.objects.get(slug=course_slug)
    reviews_count = CourseRating.objects.filter(active=True, course=course).count()
    rating_count = CourseRating.objects.filter(course=course, rating__in=["3.0", "4.0", "5.0"]).count()
    

this is how the list view look like NOTE: this is where i want to count all the rating of each course

def index(request):
    courses = Course.objects.filter(course_publish_status="published").order_by('?')

models.py

class Course(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    course_title = models.CharField(max_length=100, null=True, blank=True)
    slug = models.SlugField(unique=True)
    course_category = models.ForeignKey(Category, on_delete=models.DO_NOTHING, null=True, blank=True, related_name="courses")
    course_publish_status = models.CharField(max_length=10000, choices=COURSE_PUBLISH_STATUS, default="in_review")
    


class CourseRating(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    course = models.ForeignKey(Course, on_delete=models.CASCADE, null=True, related_name="ratings")
    rating = models.CharField(max_length=1000, choices=USER_COURSE_RATING)
    review = models.TextField()
    date = models.DateTimeField(auto_now_add=True)
    active = models.BooleanField(default=False)
    
    def __str__(self):
        return f"{self.course.course_title} - {self.rating}"
    
    class Meta:
        verbose_name = "Course Reviews and Ratings"

Upvotes: 0

Views: 821

Answers (1)

henriquesalvaro
henriquesalvaro

Reputation: 1272

What you're looking for is Aggregation the docs have some pretty good (and quick) examples of how to achieve it. You're looking to use an .annotate with the Count object. Judging by your filtering for ratings, you'll also want to use the filter= parameter of the Count object. I also highly suggest you look into how to properly use the Q() object.

With all that being said, an example to achieve what you're looking for:

courses = Course.objects.filter(
    course_publish_status="published",
).annotate(
    rating_count=Count(
        'ratings', 
        filter=Q(ratings__rating__in=["3.0", "4.0", "5.0"])
    )
).order_by("?")

Keep in mind that I considered you have a related_name="ratings" on your ForeignKey. For your next questions I strongly suggest sharing the models you're working with as well (or at least the relevant portions of them).

Upvotes: 1

Related Questions