0

I have a serialzer which have get_rates method. I want a way to get the rates for the driver in a better way and fast as well.

def get_rates(self, obj):
    reviews = Review.objects.filter(driver=obj)
    rate_5 = reviews.filter(customer_rate__gt=4, customer_rate__lte=5).count()
    rate_4 = reviews.filter(customer_rate__gt=3, customer_rate__lte=4).count()
    rate_3 = reviews.filter(customer_rate__gt=2, customer_rate__lte=3).count()
    rate_2 = reviews.filter(customer_rate__gt=1, customer_rate__lte=2).count()
    rate_1 = reviews.filter(customer_rate__gt=0, customer_rate__lte=1).count()
    return {
        'rate_5': rate_5,
        'rate_4': rate_4,
        'rate_3': rate_3,
        'rate_2': rate_2,
        'rate_1': rate_1,
    }
jarlh
  • 42,561
  • 8
  • 45
  • 63
Mahmoud Nasser
  • 805
  • 3
  • 16
  • First of all isn't `customer_rate__gt=4, customer_rate__lte=5` the same as `customer_rate=5`? Second, does this answer your question? [How to query as GROUP BY in django?](https://stackoverflow.com/questions/629551/how-to-query-as-group-by-in-django) – Yevhen Kuzmovych Oct 04 '22 at 10:20
  • no because the rate is a double value...like 3.2 it will map to 4 and 2.8 will map to 3 and so on – Mahmoud Nasser Oct 04 '22 at 10:34

1 Answers1

0
from django.db.models import Count, Q

def get_rates(self, obj):
    reviews = Review.objects.filter(driver=obj).annotate(
        rate_5=Count('pk', filter=Q(customer_rate__gt=4),
        rate_4=Count('pk', filter=Q(Q(customer_rate__gt=3) & Q( customer_rate__lte=4))),
        rate_3=Count('pk', filter=Q(Q(customer_rate__gt=2) & Q( customer_rate__lte=3))),
        rate_2=Count('pk', filter=Q(Q(customer_rate__gt=1) & Q( customer_rate__lte=2))),
        rate_1=Count('pk', filter=Q(customer_rate__lte=1),
    )
    
    # example
    for review in reviews:
        print(f"{review} has {review.rate_4} three to four star ratings.")

this will result in a single db hit and perform the count inside the db which is way faster.

hanspeters205
  • 381
  • 2
  • 6