You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将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>/:获取单个Schema
  • PUT/PATCH /schemas/<pk>/:修改单个Schema
  • DELETE /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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 15:15:31