Reputation: 159
I have the following structure in my Django models.
ratings.models.py
class Rating(models.Model):
class Meta:
verbose_name = 'Rating'
verbose_name_plural = 'Ratings'
unique_together = [
'user',
'product']
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='user')
product = models.ForeignKey(
Product,
on_delete=models.CASCADE,
related_name='product')
rating = models.PositiveIntegerField(
null=False,
blank=False)
Product
has nothing special to show here. Just a simple Django model. I will omit it.
In ProductDetailView in serializers i need the count per rating. A product can be rated from 1 to 5. Example:
{
...
"ratings": {
"rating1_star": 6,
"rating2_star": 5,
"rating3_star": 4,
"rating4_star": 3,
"rating5_star": 3
}
I have achieved this with the following code.
class ProductDetailSerializer(serializers.ModelSerializer):
ratings = serializers.SerializerMethodField('get_ratings_detail')
class Meta:
model = Product
fields = [...,'ratings',]
def get_ratings_detail(self, obj):
ratings = Rating.objects.filter(
product=obj)
r_details = ratings.aggregate(
rating1=Count(
'product',
filter=Q(rating__iexact=1)),
rating2=Count(
'product',
filter=Q(rating__iexact=2)),
rating3=Count(
'product',
filter=Q(rating__iexact=3)),
rating4=Count(
'product',
filter=Q(rating__iexact=4)),
rating5=Count(
'product',
filter=Q(rating__iexact=5)),
)
return r_details
My question is if can i achieve the same result using a better method?
I quite do not like how get_ratings_detail
looks like, and also i am not sure if this is the best way to do it.
Thank you.
Upvotes: 0
Views: 1564
Reputation: 43310
I'd just get the ratings values, use a counter, and then parse that out as required...
from collections import Counter
ratings = Counter(ratings.values_list("rating", flat=True))
For example,
>>> {f"rating{star}_star": count for star, count in ratings.items()}
{'rating5_star': 1, 'rating2_star': 2, 'rating3_star': 2, 'rating4_star': 1, 'rating1_star': 1}
Upvotes: 1