'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"
Solution 1:[1]
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).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | henriquesalvaro |