Django REST Framework多对多字段序列化时出现属性错误问题
问题解决:Django REST Framework 序列化含中间表的多对多关系时的AttributeError
错误原因
你的Menu模型中dishes是指向Dish的多对多字段,默认情况下menu.dishes返回的是Dish对象的集合。但你在MenuSerializer中使用DishOrderSerializer来序列化这个字段,DRF会尝试将每个Dish实例传入DishOrderSerializer,而Dish实例并没有dish属性(这个属性属于DishOrder中间表模型),因此抛出AttributeError。
解决方案
需要让MenuSerializer序列化的是中间表DishOrder的实例,而不是Dish实例,这需要通过模型间的反向关联来实现。
步骤1:(可选但推荐)给中间表外键添加related_name
修改DishOrder模型的menu外键,添加自定义反向关联名称,让代码更清晰:
class DishOrder(models.Model): dish = models.ForeignKey(Dish, on_delete=models.SET_NULL, blank=True, null=True) # 添加related_name,方便反向查询 menu = models.ForeignKey(Menu, on_delete=models.SET_NULL, blank=True, null=True, related_name='dish_orders') quantity = models.PositiveIntegerField() def __str__(self): return self.dish.name if self.dish else "无菜品"
步骤2:修改MenuSerializer的字段映射
将dishes字段的source指向Menu到DishOrder的反向关联(如果没加related_name,默认是dishorder_set):
class MenuSerializer(serializers.ModelSerializer): # 指向反向关联的中间表实例集合 dishes = DishOrderSerializer(many=True, source='dish_orders') # 序列化自定义的cost属性 cost = serializers.FloatField(read_only=True) class Meta: model = Menu fields = '__all__'
步骤3:修复Menu的cost属性计算(可选但重要)
原cost属性只计算了菜品单价的总和,没有考虑DishOrder中的quantity数量,修改为:
from django.db.models import F, Sum class Menu(models.Model): # ... 其他字段 ... @property def cost(self): # 计算每个菜品单价*数量的总和 total = self.dish_orders.aggregate(total_cost=Sum(F('dish__price') * F('quantity')))['total_cost'] return total or 0.00
验证
修改完成后,调用MenuSerializer(all_menus, many=True)即可正确序列化菜单数据,包含每个菜品的详情和对应的数量,以及计算正确的总费用。
内容的提问来源于stack exchange,提问作者TheRoFL
相关产品推荐
相关产品推荐

