You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Rest Framework如何从嵌套关联类提取rating计算车型平均分

解决方案

问题原因

你之前的写法不生效是因为car.rates是Django ORM返回的CarRate模型对象查询集,不是字典结构,无法通过rates["rating"]的方式直接取值,getattr也不支持传入字典取值语法作为属性名。

实现方案(共两种可选)

方案1:序列化器层面实时计算(无需持久化存储,适合数据量小的场景)

直接修改CarSerializer,通过SerializerMethodField动态计算平均评分,无需额外修改视图逻辑:

class CarSerializer(serializers.ModelSerializer):
    rates = CarRateSerializer(many=True, read_only=True)
    # 新增字段覆盖模型原有avg_rating,动态计算值
    avg_rating = serializers.SerializerMethodField()

    def get_avg_rating(self, obj):
        # obj为当前序列化的Car实例
        rate_list = obj.rates.all()
        if not rate_list:
            return 0.0
        # 提取所有rating值计算平均值,保留2位小数
        total_rating = sum(rate.rating for rate in rate_list)
        return round(total_rating / len(rate_list), 2)

    def create(self, validated_data):
        rates_data = validated_data.pop("rates")
        car = Car.objects.create(**validated_data)
        for rate_data in rates_data:
            CarRate.objects.create(car_id=car, **rate_data)
        return car

    class Meta:
        model = Car
        fields = ('id', 'make', 'model','rates','avg_rating')

方案2:持久化存储平均评分(减少重复计算,适合数据量大的场景)

通过Django信号监听评分的新增、删除、修改操作,自动更新Car模型的avg_rating字段,后续直接返回存储的值即可:

  1. 首先在你的应用目录下新建signals.py,添加如下代码:
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from .models import CarRate, Car

@receiver(post_save, sender=CarRate)
@receiver(post_delete, sender=CarRate)
def update_avg_rating(sender, instance, **kwargs):
    target_car = instance.car_id
    all_rates = target_car.rates.all()
    if all_rates:
        avg = sum(r.rating for r in all_rates) / len(all_rates)
        target_car.avg_rating = round(avg, 2)
    else:
        target_car.avg_rating = 0.0
    target_car.save(update_fields=['avg_rating'])
  1. 在应用的apps.py中注册信号:
from django.apps import AppConfig

class 你的应用名Config(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = '你的应用名'

    def ready(self):
        import 你的应用名.signals

如果你需要直接在views.py中提取rating值计算,写法如下:

# 假设car是你查询得到的Car实例
all_ratings = [rate.rating for rate in car.rates.all()]
if all_ratings:
    avg_rating = sum(all_ratings) / len(all_ratings)
else:
    avg_rating = 0.0

内容的提问来源于stack exchange,提问作者wolnio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 09:06:03