先上代码:
from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import OrderingFilter from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView from utils.pagination import NewPagination from .models import Projects from .serializers import ProjectsModelSerializer class ProjectsPage(ListCreateAPIView): ''' 类视图 ''' queryset = Projects.objects.all() serializer_class = ProjectsModelSerializer filter_backends = [DjangoFilterBackend, OrderingFilter] filterset_fields = ['id', 'name', 'leader', 'programmer', 'tester'] ordering_fields = ['id', 'name', 'leader', 'programmer', 'tester'] pagination_class = NewPagination class ProjectsDetailsPage(RetrieveUpdateDestroyAPIView): queryset = Projects.objects.all() serializer_class = ProjectsModelSerializer
我们现在想将两个视图进行合并,要怎么操作呢?直接合并我们发现有以下痛点:
- 两个类视图不能合并
- 有两个相同的get方法
- 两个类视图所对应的url地址不一致
因此这里引出了视图集,将视图集与mixins结合使用,即可解决痛点
一、视图集
请求方法 | 动作(action) | 描述 |
GET | retrieve | 获取详情数据(单条) |
GET | list | 获取列表数据(多条) |
POST | create | 创建数据 |
PUT | update | 更新数据 |
PATCH | partail_update | 更新部分数据 |
DELETE | destroy | 删除数据 |
1.ViewSet类
- 继承ViewSetMixin和views.APIView
- ViewSetMixin支持action动作
- 未提供get_onject()、get_serializer()、queryset、serializer_class等,因此不支持过滤、排序和分页的操作
2.GenericViewSet类
- 继承ViewSetMixin和generic.GenericAPIView
- 提供get_onject()、get_serializer()、queryset、serializer_class等,支持过滤、排序和分页的操作
- 在定义路由时,需要将请求方法与action动作进行绑定
- 使用Mixin类简化程序
3.ReadOnlyModelViewSet类
- 继承mixins.RetrieveModelMixin、mixins.ListModelMixin和generic.GenericAPIView
4.ModelViewSet类
- 继承mixins.CreateModelMixin、mixins.RetrieveModelMixin、mixins.UpdateModelMixin、mixins.DestroyModelMixin、mixins.ListModelMixin和generic.GenericAPIView
开始的代码优化如下:
from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import OrderingFilter from rest_framework.viewsets import GenericViewSet from rest_framework import mixins from utils.pagination import NewPagination from .models import Projects from .serializers import ProjectsModelSerializer class ProjectsPageSet(mixins.ListModelMixin, mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericViewSet): ''' 类视图 ''' queryset = Projects.objects.all() serializer_class = ProjectsModelSerializer filter_backends = [DjangoFilterBackend, OrderingFilter] filterset_fields = ['id', 'name', 'leader', 'programmer', 'tester'] ordering_fields = ['id', 'name', 'leader', 'programmer', 'tester'] pagination_class = NewPagination
关于继承,可以使用ModelViewSet替换所有的继承:
from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import OrderingFilter from rest_framework.viewsets import ModelViewSet from utils.pagination import NewPagination from .models import Projects from .serializers import ProjectsModelSerializer class ProjectsPageSet(ModelViewSet): ''' 类视图 ''' queryset = Projects.objects.all() serializer_class = ProjectsModelSerializer filter_backends = [DjangoFilterBackend, OrderingFilter] filterset_fields = ['id', 'name', 'leader', 'programmer', 'tester'] ordering_fields = ['id', 'name', 'leader', 'programmer', 'tester'] pagination_class = NewPagination
二、Routers路由
- 视图类继承了视图集之后,支持在定义路由时指定请求方法与action进行映射
- as_view()需要接收一个字典,key为请求方法名,value为指定需要调用的action
from django.contrib import admin from django.urls import path from projects.views import ProjectsPageSet urlpatterns = [ path('admin/', admin.site.urls), path('projects/', ProjectsPageSet.as_view({ 'get': 'list', 'post': 'create' })), path('projects/<int:pk>/', ProjectsPageSet.as_view({ 'get': 'retrieve', 'put': 'update', 'delete': 'destroy' })) ]
针对路由依然可以做优化
1.SimpleRouter
1.引入方式
from rest_framework.routers import SimpleRouter
2.创建路由对象
router = SimpleRouter()
3.注册路由
router对象传入的参数,prefix为指定路由前缀(r'子应用名小写',如果是在子应用下定义路由,可以设置为空),viewset直接指定视图集类
router.register(prefix=r'projects', viewset=ProjectsPageSet)
4.添加路由
使用路由对象.urls属性来获取自动生成的路由条目,获取的值为一个列表,并将该列表添加到urlpatterns列表中
urlpatterns += router.urls
5.访问根路径
如果不想根路径返回404页面,那么可以用下面这种方式
2.DefaultRouter
1.引入方式
from rest_framework.routers import DefaultRouter
2.创建对象
router = DefaultRouter()
后面的步骤一致