将Django Rest Framework的APIView转为ModelViewSet并支持批量POST
方案可行性与实现步骤
转ModelViewSet是完全可行的,而且是符合DRF(Django REST Framework)最佳实践的做法——它能自动提供RESTful风格的CRUD接口,同时你可以通过重写方法轻松扩展批量处理逻辑。当然也可以继续用APIView改造,但ModelViewSet复用性更强,后续扩展单个Schema的修改、删除等功能更省心。
下面是具体的转换和实现步骤:
1. 先优化模型(可选但强烈建议)
你的Schema模型中,周数应该是唯一的(同一周只能有一条记录),所以给week字段加上unique=True约束,从数据库层面避免重复,也能简化后续逻辑:
from django.db import models from django.core.validators import MinValueValidator, MaxValueValidator class Schema(models.Model): week = models.PositiveIntegerField( validators=[MinValueValidator(1), MaxValueValidator(53)], unique=True # 新增:保证周数唯一 ) users = models.ManyToManyField(MyUser, related_name="schemas") # 建议修改related_name,避免和用户模型的字段重名 class Meta: ordering = ('week',)
2. 调整序列化器
需要让序列化器支持批量验证,同时处理user_ids与users多对多字段的映射:
from rest_framework import serializers from .models import Schema, MyUser class SchemaSerializer(serializers.ModelSerializer): # 用user_ids接收前端传的用户ID数组,映射到users字段 user_ids = serializers.PrimaryKeyRelatedField( many=True, queryset=MyUser.objects.all(), source='users' ) class Meta: model = Schema fields = ['id', 'week', 'user_ids']
3. 转换为ModelViewSet并实现批量逻辑
继承ModelViewSet,重写create方法以同时支持单个/批量数据提交:
from rest_framework import viewsets, status from rest_framework.response import Response from .models import Schema from .serializers import SchemaSerializer from .permissions import SchemaPermissions class SchemaViewSet(viewsets.ModelViewSet): queryset = Schema.objects.all() serializer_class = SchemaSerializer permission_classes = (SchemaPermissions,) def create(self, request, *args, **kwargs): # 判断请求数据是单个对象还是数组 is_bulk = isinstance(request.data, list) # 初始化序列化器,many=True处理批量数据 serializer = self.get_serializer(data=request.data, many=is_bulk) serializer.is_valid(raise_exception=True) result_schemas = [] if is_bulk: # 处理批量数据 for item in serializer.validated_data: # 存在则获取,不存在则创建 schema, _ = Schema.objects.get_or_create(week=item['week']) schema.users.set(item['users']) result_schemas.append(schema) response_serializer = self.get_serializer(result_schemas, many=True) else: # 处理单个数据 schema, created = Schema.objects.get_or_create(week=serializer.validated_data['week']) schema.users.set(serializer.validated_data['users']) response_serializer = self.get_serializer(schema) # 根据是否创建新资源返回对应状态码 return_status = status.HTTP_201_CREATED if is_bulk or created else status.HTTP_200_OK return Response(response_serializer.data, status=return_status)
注:ModelViewSet默认已经提供了list(对应原APIView的get方法)、retrieve、update等接口,不用再手动编写。
4. 配置路由
用DRF的DefaultRouter自动生成RESTful路由,无需手动写多个URL:
from django.urls import path, include from rest_framework.routers import DefaultRouter from .views import SchemaViewSet router = DefaultRouter() # 注册路由,前缀为schemas router.register(r'schemas', SchemaViewSet) urlpatterns = [ path('', include(router.urls)), ]
生成的路由包括:
GET /schemas/:获取所有Schema(对应原APIView的get)POST /schemas/:提交单个或批量Schema(支持你要的功能)GET /schemas/<pk>/:获取单个SchemaPUT/PATCH /schemas/<pk>/:修改单个SchemaDELETE /schemas/<pk>/:删除单个Schema
补充说明
- 原代码中
Schema.objects.get(week = week).first()是错误写法:get()返回单个对象,没有first()方法,用get_or_create或filter(week=week).first()更安全。 - 如果不想用
ModelViewSet,也可以继续用APIView,在post方法里判断request.data是否为列表,然后循环处理——但ModelViewSet更符合REST规范,后续扩展成本更低。
内容的提问来源于stack exchange,提问作者wardz
相关产品推荐
相关产品推荐

