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字段,后续直接返回存储的值即可:
- 首先在你的应用目录下新建
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'])
- 在应用的
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
相关产品推荐
相关产品推荐

