Django REST Framework(DRF)PATCH 方法部分更新全解析与实战

在 RESTful API 设计中,部分更新是一种非常常见的需求。Django REST Framework(DRF)对 HTTP 的 PATCH 方法提供了原生支持,但在实际开发中,很多开发者会遇到 validated_data 为空、数据库没有更新等问题。本文将从 HTTP 原理、DRF 支持、请求方式、Serializer 与 ViewSet 使用方法、以及实际开发中常见问题的排查方法进行全面解析,并给出可直接使用的示例。


一、HTTP PATCH 方法简介

HTTP 协议提供了多种请求方法,其中:

  • GET:查询资源
  • POST:新建资源
  • PUT:整体替换资源
  • PATCH:部分更新资源
  • DELETE:删除资源

PATCH 方法与 PUT 最大的区别在于,它只修改资源中指定的字段,而不影响未指定的字段,非常适合在前端只需要更新部分数据的场景。

例如,对于某个材料清单资源:

http 复制代码
PATCH /materials/1
Content-Type: application/json

{
  "material_count": 20
}

表示仅修改 material_count 字段,其余字段保持不变。相比之下,PUT 请求需要提交完整资源数据,否则未提交的字段可能会被置空。


二、DRF 对 PATCH 的支持

在 DRF 中,只要使用 UpdateModelMixin 或者继承 ModelViewSet,就自动支持 PUT 与 PATCH 请求。例如:

python 复制代码
class MaterialViewSet(mixins.UpdateModelMixin,
                      mixins.ListModelMixin,
                      viewsets.GenericViewSet):
    queryset = IcEngineeringChecklistMaterials.objects.all()
    serializer_class = ChecklistMaterialSerializer

默认路由情况下:

URL HTTP 方法 功能
/materials/{id}/ PUT 全量更新
/materials/{id}/ PATCH 部分更新

无需额外编写 action,就可以直接使用 PATCH 实现部分更新。


三、PATCH 请求的正确使用方式

DRF 默认只从请求体(body)读取 PATCH 数据,而不会从查询参数(params)中读取。这是许多开发者在实际开发中遇到 validated_data 为空的根本原因。

正确示例

前端使用 Axios:

js 复制代码
axios.patch("/api/materials/1/", {
    unit: "kg",
    material_count: 5
}, {
    headers: { "Content-Type": "application/json" }
});

或者使用 fetch:

js 复制代码
fetch("/api/materials/1/", {
    method: "PATCH",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        unit: "kg",
        material_count: 5
    })
});

错误示例(不可用):

http 复制代码
PATCH /materials/1?unit=kg

因为 DRF 不会把 query 参数作为 request.data 处理,Serializer 无法接收到数据,validated_data 将为空。


四、Serializer 部分更新写法

对于部分更新,通常会定义一个专门的 Serializer,只包含可更新字段:

python 复制代码
class ChecklistMaterialPartialUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = IcEngineeringChecklistMaterials
        fields = ['material_count', 'deadline_arrive', 'brand', 'unit']

如果某些字段修改需要额外逻辑(例如单位转换),可以在 update() 方法中实现:

python 复制代码
def update(self, instance, validated_data):
    if 'unit' in validated_data:
        new_unit = validated_data['unit']
        old_unit = instance.unit
        if old_unit != new_unit:
            # 示例:单位转换逻辑
            instance.material_count = convert_count(instance.material_count, old_unit, new_unit)
        instance.unit = new_unit

    for field in ['material_count', 'brand', 'deadline_arrive']:
        if field in validated_data:
            setattr(instance, field, validated_data[field])

    instance.save()
    return instance

注意

  • validated_data 不会自动写入 Model,必须通过 setattrsuper().update() 显式赋值。
  • return instance 返回的是修改后的对象(前提是你已经修改并保存了字段)。

五、ViewSet 中 get_serializer_class 写法

如果你的 ViewSet 中不同操作使用不同的 Serializer,可以通过 get_serializer_class 动态返回:

python 复制代码
def get_serializer_class(self):
    if self.action == 'partial_update':
        return ChecklistMaterialPartialUpdateSerializer
    return ChecklistSerializer

六、PATCH 常见问题排查

当发现 PATCH 不生效时,可以按照以下步骤排查:

  1. 检查 request.data 是否有内容

    打印 request.data,确保前端将数据放在请求体 JSON 中,而不是 params。

  2. 检查 serializer 校验是否通过

    使用 serializer.is_valid(raise_exception=True),确保字段验证通过。

  3. 检查 validated_data 是否为空

    打印 serializer.validated_data

  4. 检查 update 是否真正写入数据库

    可以通过 Django Admin 或直接查询数据库验证。


七、最终推荐模板

Serializer

python 复制代码
class ChecklistMaterialPartialUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = IcEngineeringChecklistMaterials
        fields = ['material_count', 'deadline_arrive', 'brand', 'unit']

    def update(self, instance, validated_data):
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        return instance

ViewSet

python 复制代码
class MaterialViewSet(mixins.UpdateModelMixin,
                      mixins.ListModelMixin,
                      viewsets.GenericViewSet):
    queryset = IcEngineeringChecklistMaterials.objects.all()

    def get_serializer_class(self):
        if self.action == 'partial_update':
            return ChecklistMaterialPartialUpdateSerializer
        return ChecklistSerializer

八、总结

  1. PATCH 用于部分更新,只修改指定字段,不影响未指定字段。
  2. DRF 自动支持 PATCH,只需继承 UpdateModelMixin 或 ModelViewSet。
  3. 请求体必须使用 JSON,参数不要放在 query params 中,否则 validated_data 会为空。
  4. Serializer.update 必须显式赋值 ,返回的 instance 是修改后的对象。
  5. 对于涉及逻辑转换的字段(如 unit),在 update 方法中处理即可。
相关推荐
摘星编程30 分钟前
OpenHarmony环境下React Native:Geolocation地理围栏
python
充值修改昵称1 小时前
数据结构基础:从二叉树到多叉树数据结构进阶
数据结构·python·算法
q_35488851533 小时前
AI大模型:python新能源汽车推荐系统 协同过滤推荐算法 Echarts可视化 Django框架 大数据毕业设计(源码+文档)✅
大数据·人工智能·python·机器学习·信息可视化·汽车·推荐算法
Yeats_Liao3 小时前
开源生态资源:昇腾社区ModelZoo与DeepSeek的最佳实践路径
python·深度学习·神经网络·架构·开源
被星1砸昏头3 小时前
掌握Python魔法方法(Magic Methods)
jvm·数据库·python
love530love4 小时前
彻底解决 ComfyUI Mixlab 插件 Whisper.available False 的报错
人工智能·windows·python·whisper·win_comfyui
不解风水4 小时前
《深度学习入门:基于 Python 的理论与实现》(斋藤康毅)
人工智能·python·深度学习
偷星星的贼114 小时前
数据分析与科学计算
jvm·数据库·python
小马爱打代码4 小时前
SpringBoot:封装 starter
java·spring boot·后端
STARSpace88884 小时前
SpringBoot 整合个推推送
java·spring boot·后端·消息推送·个推