PUT请求与PATCH请求的核心差异及DRF实现指南
一、PUT请求:完整资源替换
定义:PUT用于整体更新或创建资源,需提供资源的完整字段(即使未修改的字段也需包含),若资源不存在则可能创建新资源。
关键特性:
- 幂等性:多次执行相同PUT请求结果一致(最终状态由最后一次请求决定)。
- 数据完整性:必须包含资源的所有必填字段,未提供的字段可能被重置为默认值或清空。
DRF实现示例(含文件上传):
# views.py(视图集处理PUT请求)
def update(self, request, *args, **kwargs):
instance = self.get_object()
# 需传递完整用户信息(含文件字段avatar)
serializer = self.get_serializer(instance, data=request.data)
serializer.is_valid(raise_exception=True) # 触发序列化器验证
serializer.save() # 调用序列化器update方法
return Response(serializer.data)
二、PATCH请求:部分资源更新
定义:PATCH用于增量更新资源,仅需提供待修改的字段,未提及的字段保持原有值。
关键特性:
- 非强制幂等性:若更新逻辑为“增加库存10”,重复调用会导致库存持续增加(需通过业务逻辑保证幂等性)。
- 数据局部性:仅传递变化的字段,减少网络传输量。
DRF实现示例:
# views.py(视图集处理PATCH请求)
def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
# 仅传递需修改的字段(如仅更新avatar或username)
serializer = self.get_serializer(instance, data=request.data, partial=True) # partial=True允许部分更新
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
三、核心差异对比
维度 |
PUT请求 |
PATCH请求 |
更新范围 |
完整覆盖资源 |
仅修改指定字段 |
请求体要求 |
必须包含所有必填字段 |
仅包含待修改字段 |
幂等性 |
天然幂等(多次执行结果一致) |
需业务逻辑保证幂等性 |
适用场景 |
全量替换(如用户信息重置) |
局部修改(如更新头像、邮箱) |
四、DRF文件上传的企业级实现(PUT/PATCH通用)
①1. 前端请求格式(Axios示例)
// 必须使用FormData传递文件+普通字段
const formData = new FormData();
formData.append('avatar', file); // 文件字段(二进制流)
formData.append('username', 'new_username'); // 普通字段
axios.patch('/api/users/1/', formData, {
headers: {'Content-Type': 'multipart/form-data'}
});
②2. 后端核心配置
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.MultiPartParser', # 解析文件
'rest_framework.parsers.JSONParser', # 解析JSON
]
}
③3. 序列化器文件验证与处理
# serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'avatar']
def validate_avatar(self, value):
# 企业级验证:文件类型+大小限制
if value.size > 5 * 1024 * 1024: # 5MB
raise serializers.ValidationError("文件大小不能超过5MB")
return value
def update(self, instance, validated_data):
# 仅更新传递的字段(支持PUT/PATCH)
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
return instance
五、企业级最佳实践
1. 优先使用PATCH处理文件上传
o 减少无效字段传输,避免因遗漏字段导致数据丢失。
o 在视图集默认开启partial=True:def get_serializer(self, *args, **kwargs):
kwargs.setdefault('partial', True) # 全局支持部分更新
return super().get_serializer(*args, **kwargs)
2. 文件存储与安全
o 使用云存储(如AWS S3、阿里云OSS)替代本地存储:DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
o 限制文件访问权限:生成带过期时间的签名URL(如django-storages自动支持)。
3. 异步处理大文件
o 用Celery异步生成缩略图或扫描病毒:@shared_task
def process_avatar(user_id):
user = User.objects.get(id=user_id)
generate_thumbnail(user.avatar.path) # 生成缩略图
六、常见问题排查
- 400错误“文件字段缺失”:PUT请求未传递完整字段,需补充所有必填项。
- 415错误“不支持的媒体类型”:未配置MultiPartParser或前端未设置multipart/form-data。
- 文件验证失败:检查序列化器validate_<field>方法中的类型/大小限制。
通过严格区分PUT/PATCH语义,并结合DRF的序列化器验证与文件处理机制,可构建安全、高效的企业级API。