如何向Django模型批量POST/PATCH JSON:API格式对象?
实现JSON:API规范的批量POST和PATCH功能(Django REST Framework JSON:API)
你已经基于Django REST Framework JSON:API搭好了基础的资源查询功能,要实现批量创建(POST)和批量更新(PATCH),需要调整序列化器和视图集,同时适配JSON:API的批量数据格式,下面是具体的修改步骤:
1. 调整Serializer,完善关系字段映射
你的现有Serializer用了__all__,但为了正确解析JSON:API格式的relationships数据,需要显式定义ResourceRelatedField,确保关系字段能正确关联到对应模型:
from rest_framework_json_api import serializers from proposal.models import Organization, ProposalConfigurableFields, OptionalFieldsByOrganization from rest_framework_json_api.relations import ResourceRelatedField class OptionalFieldsByOrganizationSerializer(serializers.ModelSerializer): # 显式声明关系字段,匹配JSON:API的relationships结构 organization = ResourceRelatedField(queryset=Organization.objects.all()) configurable_fields = ResourceRelatedField(queryset=ProposalConfigurableFields.objects.all()) class Meta: model = OptionalFieldsByOrganization fields = ['id', 'status', 'organization', 'configurable_fields'] # 可选:如果需要返回关联资源的完整数据,可开启include配置 # include = ['organization', 'configurable_fields']
2. 修改ViewSet,实现批量处理逻辑
Django REST Framework JSON:API本身支持批量操作,但需要在ViewSet中重写create和update方法,判断请求是否为批量格式并处理:
from sis_common.views import BaseViewSet from proposal.models import OptionalFieldsByOrganization from proposal.serializers.optional_fields_by_organization import OptionalFieldsByOrganizationSerializer from rest_framework.response import Response from rest_framework import status class OptionalFieldsByOrganizationViewSet(BaseViewSet): queryset = OptionalFieldsByOrganization.objects.all().order_by('pk') serializer_class = OptionalFieldsByOrganizationSerializer def create(self, request, *args, **kwargs): # 判断是否为批量请求(data是数组格式) is_bulk = isinstance(request.data.get('data'), list) if is_bulk: serializers = [] for item in request.data['data']: # 单条数据序列化验证 serializer = self.get_serializer(data={'data': item}) serializer.is_valid(raise_exception=True) self.perform_create(serializer) serializers.append(serializer) # 整理批量创建的响应数据 response_data = [serializer.data for serializer in serializers] return Response({'data': response_data}, status=status.HTTP_201_CREATED) # 单条创建沿用父类逻辑 return super().create(request, *args, **kwargs) def update(self, request, *args, **kwargs): # 判断是否为批量更新请求 is_bulk = isinstance(request.data.get('data'), list) if is_bulk: updated_data = [] for item in request.data['data']: # 根据id获取要更新的实例 instance = self.get_queryset().get(pk=item['id']) # 部分更新(PATCH),partial=True允许只传修改的字段 serializer = self.get_serializer(instance, data={'data': item}, partial=True) serializer.is_valid(raise_exception=True) self.perform_update(serializer) updated_data.append(serializer.data) return Response({'data': updated_data}, status=status.HTTP_200_OK) # 单条更新沿用父类逻辑 return super().update(request, *args, **kwargs)
3. 关键补充配置
- 唯一性约束:为避免同一个
organization和configurable_fields重复创建,建议在模型的Meta中添加联合唯一约束:class Meta: permissions = ( ('view_optionalfieldsbyorganization', 'Can view Optional Fields By Organization'), ('add_optionalfieldsbyorganization', 'Can add Optional Fields By Organization'), ('change_optionalfieldsbyorganization', 'Can change Optional Fields By Organization'),) unique_together = ('organization', 'configurable_fields') - 权限校验:确保你的
BaseViewSet已经配置了对应的添加、修改权限,否则批量操作会被拦截。
测试示例
批量POST创建请求
用curl测试你提供的示例payload:
curl -X POST \ http://localhost:8000/v1/optionalfieldsbyorganizations \ -H 'Authorization: Basic YWRtaW46YWRtaW4xMjM=' \ -H 'Content-Type: application/vnd.api+json' \ -d '{ "data": [ { "type": "OptionalFieldsByOrganization", "attributes": { "status": 2 }, "relationships": { "organization": { "data": { "type": "Organization", "id": "2" } }, "configurable_fields": { "data": { "type": "ProposalConfigurableFields", "id": "2" } } } },{ "type": "OptionalFieldsByOrganization", "attributes": { "status": 1 }, "relationships": { "organization": { "data": { "type": "Organization", "id": "2" } }, "configurable_fields": { "data": { "type": "ProposalConfigurableFields", "id": "3" } } } } ] }'
批量PATCH更新请求
假设要更新id为1和2的记录:
curl -X PATCH \ http://localhost:8000/v1/optionalfieldsbyorganizations \ -H 'Authorization: Basic YWRtaW46YWRtaW4xMjM=' \ -H 'Content-Type: application/vnd.api+json' \ -d '{ "data": [ { "type": "OptionalFieldsByOrganization", "id": "1", "attributes": { "status": 0 } },{ "type": "OptionalFieldsByOrganization", "id": "2", "attributes": { "status": 2 } } ] }'
内容的提问来源于stack exchange,提问作者Aashish P
相关产品推荐
相关产品推荐

