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 方法中处理即可。
相关推荐
微学AI2 小时前
内网穿透的应用-服务器日志出现异常怎么办?Python监控、钉钉告警与远程处理教程
服务器·python·钉钉
2601_953720828 小时前
【计算机毕业设计】基于Spring Boot的心理健康咨询与评测系统的设计与实现
java·spring boot·后端
东方小月9 小时前
从零开发一个 Coding Agent(四):使用状态机校验大模型事件流
前端·人工智能·后端
都叫我大帅哥10 小时前
“让AI修就行”?我劝你收回这句话——来自一位Java博主的硬核反常识
后端
whyfail10 小时前
前端学 Spring Boot(8):接口为什么越用越慢?
前端·spring boot·后端
_Jimmy_10 小时前
Agent 溯源精度提升方案
人工智能·python·langchain
Muscleheng11 小时前
Spring Boot 3.x 集成 DeepSeek 实现 Function Calling(工具调用)
人工智能·spring boot·后端·ai·spring ai·deepseek
@航空母舰11 小时前
SpringBoot通过Map实现天然的策略模式
java·spring boot·后端
SamChan9011 小时前
在Web应用中集成PDF多语言翻译功能:PDFTranslator API实战指南
前端·python·ai·pdf·yapi·机器翻译