Django Рамочная система отдыха Star Rating System - PullRequest
0 голосов
/ 13 марта 2020

У меня есть следующая структура в моих Django моделях.

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 не имеет ничего особенного, чтобы показать здесь. Просто простая Django модель. Я опущу это.

В ProductDetailView в сериализаторах мне нужно рассчитывать по рейтингу. Продукт может быть оценен от 1 до 5. Пример:

{
...
"ratings": {
  "rating1_star": 6,
  "rating2_star": 5,
  "rating3_star": 4,
  "rating4_star": 3,
  "rating5_star": 3
}

Я добился этого с помощью следующего кода.

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

У меня вопрос, могу ли я достичь того же результата, используя лучший метод? Мне совсем не нравится, как выглядит get_ratings_detail, а также я не уверен, что это лучший способ сделать это. Спасибо.

1 Ответ

1 голос
/ 13 марта 2020

Я бы просто получил значения оценок, использовал счетчик , а затем разобрал это, как требуется ...

from collections import Counter
ratings = Counter(ratings.values_list("rating", flat=True))

Например,

>>> {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}
...