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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:25:13