drf视图集学习
1. 五个视图扩展类和
提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。
urls.py
from django.urls import path, re_path from . import views urlpatterns = [ path("student/", views.StudentAPIView.as_view()), re_path("^student2/(?P<pk>\d+)/$", views.Student2APIView.as_view()), path("student3/", views.Student3APIView.as_view()), re_path("^student4/(?P<pk>\d+)/$", views.Student4APIView.as_view()), ]
serializers.py
from rest_framework import serializers from students import models class StudentModelSerializer(serializers.ModelSerializer): class Meta: model = models.Student fields = "__all__"
views.py
from .serializers import StudentModelSerializer from students import models from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin from rest_framework.generics import GenericAPIView class StudentAPIView(GenericAPIView, ListModelMixin, CreateModelMixin): serializer_class = StudentModelSerializer queryset = models.Student.objects # 获取多条数据 def get(self, request): return self.list(request) # 提交数据 def post(self, request): return self.create(request) class Student2APIView(GenericAPIView, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin): serializer_class = StudentModelSerializer queryset = models.Student.objects # 修改一条数据 def post(self, request, pk): return self.update(request, pk) # 查询一条数据 def get(self, request, pk): return self.retrieve(request, pk) # 删除一条数据 def delete(self, request, pk): return self.destroy(request, pk)
#
from rest_framework.generics import ListAPIView, UpdateAPIView, CreateAPIView, DestroyAPIView, RetrieveAPIView, RetrieveUpdateDestroyAPIView class Student3APIView(ListAPIView, CreateAPIView): serializer_class = StudentModelSerializer queryset = models.Student.objects # class Student4APIView(UpdateAPIView, DestroyAPIView, RetrieveAPIView): class Student4APIView(RetrieveUpdateDestroyAPIView): serializer_class = StudentModelSerializer queryset = models.Student.objects
2. 视图集Viewset :
使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:
list() 提供一组数据
retrieve() 提供单个数据
create() 创建数据
update() 保存数据
destory() 删除数据
ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。
视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上
使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,
所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与`GenericAPIView`,所以还需要继承`GenericAPIView`。 GenericViewSet就帮助我们完成了这样的继承工作,继承自`GenericAPIView`与`ViewSetMixin`,
在实现了调用as_view()时传入字典(如`{'get':'list'}`)的映射处理工作的同时,还提供了`GenericAPIView`提供的基础方法,可以直接搭配Mixin扩展类使用。
视图集
继承自`GenericViewSet`,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
继承自`GenericViewSet`,同时包括了ListModelMixin、RetrieveModelMixin。
urls.py
from django.urls import path, re_path from . import views urlpatterns = [ path("student/", views.StudentAPIViewSet.as_view({"get": "list", "post": "post"})), re_path("^student1/(?P<pk>\d+)/$",views.StudentAPIViewSet.as_view({"get": "get", "put": "put", "delete": "delete"})), path("student2/", views.Student2APIViewSet.as_view({"get": "get", "post": "post"})), re_path("^student3/(?P<pk>\d+)/$",views.Student2APIViewSet.as_view({"get": "get_one", "put": "put", "delete": "delete"})), ] # 使用路由类给视图集生成路由 from rest_framework.routers import SimpleRouter, DefaultRouter router = DefaultRouter() # router.register("路由访问前缀","视图集类","路由别名") router.register("student4", views.Student3APIViewSet, ) print(router.urls) # 把路由类生成的路由信息合并到项目中 urlpatterns += router.urls
路由说明:
DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。
views.py
from students import models from learn.serializers import StudentModelSerializer from rest_framework.viewsets import ViewSet from rest_framework.response import Response from rest_framework import status class StudentAPIViewSet(ViewSet): def list(self,request): """获取多条数据""" student_list = models.Student.objects.all() serializer = StudentModelSerializer(instance=student_list,many=True) return Response(serializer.data) def post(self,request): """添加学生信息""" serialzier = StudentModelSerializer(data=request.data) serialzier.is_valid(raise_exception=True) serialzier.save() return Response(serialzier.data) def get(self,request,pk): """获取一条数据""" student = models.Student.objects.get(pk=pk) serializer = StudentModelSerializer(instance=student) return Response(serializer.data) def put(self,request,pk): student = models.Student.objects.get(pk=pk) serializer = StudentModelSerializer(instance=student, data=request.data) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data) def delete(self,request,pk): models.Student.objects.get(pk=pk).delete() return Response(status=status.HTTP_204_NO_CONTENT) from rest_framework.viewsets import GenericViewSet # GenericViewSet视图集 class Student2APIViewSet(GenericViewSet): serializer_class = StudentModelSerializer queryset = models.Student.objects def get(self,request): """获取多条""" # serializer = self.serializer_class(instance=self.queryset.all(),many=True) serializer = self.get_serializer(instance=self.get_queryset(),many=True) return Response(serializer.data) def post(self,request): """添加信息""" serialzier = self.get_serializer(data=request.data,context={}) serialzier.is_valid(raise_exception=True) serialzier.save() return Response(serialzier.data) def get_one(self,request,pk): """获取一条数据""" # serializer = self.serializer_class(instance=self.queryset.get(pk=pk)) serializer = self.get_serializer(instance=self.get_object()) return Response(serializer.data) def put(self,request,pk): serializer = self.get_serializer(instance=self.get_object(), data=request.data) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data) def delete(self,request,pk): self.get_object().delete() return Response(status=status.HTTP_204_NO_CONTENT) # modelviewset from rest_framework.viewsets import ModelViewSet from demo.serializers import Studnet2ModelSerializers class Student3APIViewSet(ModelViewSet): serializer_class = StudentModelSerializer queryset = models.Student.objects def get_serializer_class(self): print(self.action) # 通过action对象属性来获取当前请求视图集时的action动作是哪个。 if self.action.lower() == "list": return StudentModelSerializer else: return Studnet2ModelSerializers
在视图集中自定义动作:
""" methods: 设置那些http请求方法能访问到当前视图方法 detail: 设置生成路由时,是否附带id到地址中 True: <URLPattern '^student9/(?P<pk>[^/.]+)/test_api/$' [name='student-test-api']> False: <URLPattern '^student9/test_api/$' [name='student-test-api']> url_path: 设置访问当前方法的子路由,如果不配置,则默认是是当前方法名 """ @action(methods=["get","post"],detail=True) def test_api(self,request): return Response("测试数据")