Как, например, использовать _set в SerializerMethod?

Я хочу вычислить средний рейтинг с помощью SerializerMethodField(). Ошибка в следующем коде AttributeError: 'FeedbackModel' object has no attribute 'aggregate'

Я думаю, что _set отсутствует, но я не знаю, куда его вставить...

class FeedbackSerializer(serializers.ModelSerializer):
    feedback_by_user_profile_pic = serializers.ImageField(source='feedback_by.profile_pic')
    average_rating = serializers.SerializerMethodField()

    def get_average_rating(self,instance):
        return instance.aggregate(average_rating=Avg('rating'))['average_rating']

    class Meta:
        model = FeedbackModel
        fields = ['feedback_text','rating','date','feedback_by_user_profile_pic','average_rating']

Модель обратной связи

class FeedbackModel(models.Model):
    feedback_text = models.CharField(max_length=1000)
    rating = models.IntegerField()
    date = models.DateField(auto_now=True)
    feedback_by = models.ForeignKey(UserModel,on_delete=models.CASCADE)
    business_account = models.ForeignKey(BusinessAccountModel,on_delete=models.CASCADE)
    
    class Meta:
        db_table = 'feedback'

Я думаю, что вам нужно добавить поле average_rating в BusiAccSerializer, а не в FeedbackSerializer. Сначала вам нужно установить атрибут related_name в FeedbackModel.

class FeedbackModel(models.Model):
    ...
    # here I added the `related_name` attribute
    business_account = models.ForeignKey(BusinessAccountModel,on_delete=models.CASCADE, related_name="feedbacks")
    

А затем в BusiAccSerializer,

class BusiAccSerializer(serializers.ModelSerializer):
    average_rating = serializers.SerializerMethodField(read_only = True)

    def get_average_rating(self, obj):
        return obj.feedbacks.aggregate(average_rating = Avg('rating'))['average_rating']

    class Meta:
        model = BusinessAccountModel
        fields = (
            'business_title', 'business_description', 'status', 'note', 'user', 'average_rating',
        )

Прежде всего, вы указали, что вам нужен средний рейтинг для бизнес-счета, но вы не можете получить средний рейтинг для счета, не имея конкретного бизнес-счета, поэтому вам нужно сделать это в сериализаторе бизнес-счетов.

Дэвид Лу уже ответил, как это сделать в BusiAccSerializer, но у меня есть что добавить: То, что вы пытаетесь сделать, это использовать поле метода сериализатора для добавления некоторых агрегированных данных на выходе. Этот способ решения вашей проблемы имеет существенный недостаток: когда вы попытаетесь сериализовать список BusinessAccountModels, сериализатор будет делать отдельный вызов базы данных для каждого бизнес-счета, и это может быть медленным. Лучше указать аннотированный кверисет в представлении следующим образом:

BusinessAccountModel.objects.all().annotate(average_rating=Avg('feedbacks__rating'))

Тогда вы сможете использовать результат вычисления как обычное поле в вашем сериализаторе:

class BusiAccSerializer(serializers.ModelSerializer):
    ...
    average_rating = serializers.FloatField(read_only=True)

Таким образом, сериализатор не будет выполнять дополнительных запросов к базе данных.

Вернуться на верх