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 方法中处理即可。
相关推荐
天天爱吃肉821824 分钟前
【跨界封神|周杰伦×王传福(陶晶莹主持):音乐创作与新能源NVH测试,底层逻辑竟完全同源!(新人必看入行指南)】
python·嵌入式硬件·算法·汽车
岱宗夫up37 分钟前
Python 数据分析入门
开发语言·python·数据分析
码界筑梦坊39 分钟前
325-基于Python的校园卡消费行为数据可视化分析系统
开发语言·python·信息可视化·django·毕业设计
asheuojj42 分钟前
2026年GEO优化获客效果评估指南:如何精准衡量TOP5关
大数据·人工智能·python
多恩Stone43 分钟前
【RoPE】Flux 中的 Image Tokenization
开发语言·人工智能·python
李日灐1 小时前
C++进阶必备:红黑树从 0 到 1: 手撕底层,带你搞懂平衡二叉树的平衡逻辑与黑高检验
开发语言·数据结构·c++·后端·面试·红黑树·自平衡二叉搜索树
网安墨雨1 小时前
Python自动化一------pytes与allure结合生成测试报告
开发语言·自动化测试·软件测试·python·职场和发展·自动化
powerfulhell1 小时前
寒假python作业5
java·前端·python
铉铉这波能秀1 小时前
LeetCode Hot100 中 enumerate 函数的妙用(2026.2月版)
数据结构·python·算法·leetcode·职场和发展·开发
毕设源码-赖学姐1 小时前
【开题答辩全过程】以 基于python的电影推荐系统为例,包含答辩的问题和答案
开发语言·python