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

Django REST Framework向Serializer传递URL中recipe_id的最优方案

Django DRF 嵌套路由下向外键关联Serializer传递参数的最优方案

现有实现的问题

你目前直接修改request.data的方式存在两个明显缺陷:

  • Django原生请求的request.data默认是不可变的QueryDict对象,直接赋值会抛出AttributeError: This QueryDict instance is immutable错误,只有部分DRF解析器返回的可变字典支持该操作,兼容性很差。
  • 逻辑分层不清晰:路径参数的补充逻辑和序列化校验逻辑耦合,不符合DRF的设计规范。

最优改造方案

第一步:序列化器调整

把外键recipe字段设为只读,避免用户提交的请求篡改关联关系,也不需要再校验用户传入的recipe参数合法性:

# serializers.py
class IngredientSerializer(serializers.ModelSerializer):
    class Meta:
        model = Ingredient
        fields = [
            'id',
            'name',
            'quantity',
            'unit',
            'recipe'
        ]
        # 新增该行,把recipe设为只读字段,用户提交的参数中该字段会被忽略
        read_only_fields = ['recipe']

第二步:视图层调整

不需要重写整个create方法,只要重写DRF提供的perform_create钩子(专门用于保存实例前补充额外字段),同时补充get_queryset方法,符合嵌套路由recipes/{recipe.id}/ingredients的语义,只返回对应食谱下的食材列表:

# views.py
class IngredientViewSet(viewsets.ModelViewSet):
    serializer_class = IngredientSerializer

    # 只返回当前路径对应食谱的食材列表
    def get_queryset(self):
        return Ingredient.objects.filter(recipe_id=self.kwargs['pk'])

    # 保存前补充recipe外键参数
    def perform_create(self, serializer):
        serializer.save(recipe_id=self.kwargs['pk'])

方案优势

  • 无兼容性问题:不需要修改不可变的request.data,适配所有请求类型和解析器
  • 逻辑清晰:序列化器负责校验用户传入的合法字段,视图层负责处理路径参数注入,符合分层设计规范
  • 代码精简:不需要重写整个create方法的冗余逻辑,只用实现必要的自定义逻辑
  • 安全性更高:recipe设为只读字段后,即使用户请求中携带错误的recipe参数也会被序列化器直接忽略,不会出现关联错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 06:27:03