drf之视图扩展类(混入类)
### 1.2.2 5个视图扩展类 - 也叫混入类。
作用: 提供了几种后端视图(对数据资源进行增删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。 这五个扩展类需要搭配GenericAPIView通用视图基类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。
#### 1)ListModelMixin
列表视图扩展类,提供`list(request, *args, **kwargs)`方法快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。
源代码:
class ListModelMixin(object): """ List a queryset. """ def list(self, request, *args, **kwargs): # 过滤 queryset = self.filter_queryset(self.get_queryset()) # 分页 page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) # 序列化 serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)
举例:
from rest_framework.mixins import ListModelMixin,CreateModelMixin class StudentMixinAPIView(GenericAPIView,ListModelMixin,CreateModelMixin): serializer_class = StudentModelSerializer queryset = Student.objects def get(self,request,*args,**kwargs): """获取所有模型信息""" return self.list(request,*args,**kwargs)
#### 2)CreateModelMixin
创建视图扩展类,提供`create(request, *args, **kwargs)`方法快速实现创建资源的视图,成功返回201状态码。
如果序列化器对前端发送的数据验证失败,返回400错误。
源代码:
class CreateModelMixin(object): """ Create a model instance. """ def create(self, request, *args, **kwargs): # 获取序列化器 serializer = self.get_serializer(data=request.data) # 验证 serializer.is_valid(raise_exception=True) # 保存 self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) def perform_create(self, serializer): serializer.save() def get_success_headers(self, data): try: return {'Location': str(data[api_settings.URL_FIELD_NAME])} except (TypeError, KeyError): return {}
视图代码
from rest_framework.mixins import ListModelMixin,CreateModelMixin class StudentMixinAPIView(GenericAPIView,ListModelMixin,CreateModelMixin): serializer_class = StudentModelSerializer queryset = Student.objects def get(self,request,*args,**kwargs): """获取所有模型信息""" return self.list(request,*args,**kwargs) def post(self,request): """添加一个模型信息""" return self.create(request)
#### 3)RetrieveModelMixin
详情视图扩展类,提供`retrieve(request, *args, **kwargs)`方法,可以快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。
源代码:
class RetrieveModelMixin(object): """ Retrieve a model instance. """ def retrieve(self, request, *args, **kwargs): # 获取对象,会检查对象的权限 instance = self.get_object() # 序列化 serializer = self.get_serializer(instance) return Response(serializer.data)
视图代码:
from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin class Student1MixinAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): serializer_class = StudentModelSerializer queryset = Student.objects def get(self,request,pk): """获取一个模型信息""" return self.retrieve(request,pk)
#### 4)UpdateModelMixin
更新视图扩展类,提供`update(request, *args, **kwargs)`方法,可以快速实现更新一个存在的数据对象。
同时也提供`partial_update(request, *args, **kwargs)`方法,可以实现局部更新。
成功返回200,序列化器校验数据失败时,返回400错误。
源代码:
class UpdateModelMixin(object): """ Update a model instance. """ def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) serializer.is_valid(raise_exception=True) self.perform_update(serializer) if getattr(instance, '_prefetched_objects_cache', None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. instance._prefetched_objects_cache = {} return Response(serializer.data) def perform_update(self, serializer): serializer.save() def partial_update(self, request, *args, **kwargs): kwargs['partial'] = True return self.update(request, *args, **kwargs)
视图代码:
from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin class Student1MixinAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): serializer_class = StudentModelSerializer queryset = Student.objects def get(self,request,pk): """获取一个模型信息""" return self.retrieve(request,pk) def put(self,request,pk): """更新一个模型信息""" return self.update(request,pk)
#### 5)DestroyModelMixin
删除视图扩展类,提供`destroy(request, *args, **kwargs)`方法,可以快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。
源代码:
class DestroyModelMixin(object): """ Destroy a model instance. """ def destroy(self, request, *args, **kwargs): instance = self.get_object() self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT) def perform_destroy(self, instance): instance.delete()
视图代码:
from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin class Student1MixinAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): serializer_class = StudentModelSerializer queryset = Student.objects def get(self,request,pk): """获取一个模型信息""" return self.retrieve(request,pk) def put(self,request,pk): """更新一个模型信息""" return self.update(request,pk) def delete(self,request,pk): """删除一个模型信息""" return self.destroy(request,pk)
整体代码,使用GenericAPIView结合视图扩展类,实现5个基本api接口,视图代码:
""" 使用drf内置的模型扩展类[混入类]结合GenericAPIView实现通用视图方法的简写操作 from rest_framework.mixins import ListModelMixin 获取多条数据,返回响应结果 list from rest_framework.mixins import CreateModelMixin 添加一条数据,返回响应结果 create from rest_framework.mixins import RetrieveModelMixin 获取一条数据,返回响应结果 retrieve from rest_framework.mixins import UpdateModelMixin 更新一条数据,返回响应结果 update(更新全部字段)和partial_update(更新单个或部分字段,例如修改密码,修改头像) from rest_framework.mixins import DestroyModelMixin 删除一条数据,返回响应结果 destroy """ from rest_framework.mixins import ListModelMixin, CreateModelMixin class StudentMixinView(GenericAPIView, ListModelMixin, CreateModelMixin): queryset = Student.objects.all() serializer_class = StudentModelSerializer def get(self,request): """获取所有数据""" return self.list(request) def post(self,request): """添加一条数据""" return self.create(request) from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin class StudentInfoMixinView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): queryset = Student.objects.all() serializer_class = StudentModelSerializer def get(self,request,pk): return self.retrieve(request, pk=pk) def put(self,request, pk): return self.update(request, pk=pk) def delete(self,request, pk): return self.destroy(request, pk=pk)
序列化器,代码:
from rest_framework import serializers from stuapi.models import Student class StudentModelSerializer(serializers.ModelSerializer): class Meta: model = Student fields = "__all__" extra_kwargs = { "age": { "max_value": 25, "error_messages": { "max_value": "年龄不能超过25岁!", } } }
路由代码:
from django.urls import path, re_path from . import views urlpatterns = [ # APIView path("students/", views.StudentAPIView.as_view()), re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()), # GenericAPIView path("students2/", views.StudentGenericAPIView.as_view()), re_path("^students2/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()), # GenericAPIView + mixins path("students3/", views.StudentMixinView.as_view()), re_path("^students3/(?P<pk>\d+)/$", views.StudentInfoMixinView.as_view()), ]
### 1.2.3 9个视图子类
#### 1)CreateAPIView 提供了post方法,内部调用了create方法 继承自: GenericAPIView、CreateModelMixin #### 2)ListAPIView 提供了get方法,内部调用了list方法 继承自:GenericAPIView、ListModelMixin #### 3)RetrieveAPIView 提供了get方法,内部调用了retrieve方法 继承自: GenericAPIView、RetrieveModelMixin #### 4)DestoryAPIView 提供了delete方法,内部调用了destory方法 继承自:GenericAPIView、DestoryModelMixin #### 5)UpdateAPIView 提供了put和patch方法,内部调用了update和partial_update方法 继承自:GenericAPIView、UpdateModelMixin #### 6)ListCreateAPIView 提供了get和post方法,内部调用了list和create方法 继承自:GenericAPIView、ListModelMixin、CreateModelMixin #### 7)RetrieveUpdateAPIView 提供 get、put、patch方法 继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin #### 8)RetrieveDestoryAPIView 提供 get、delete方法 继承自:GenericAPIView、RetrieveModelMixin、DestoryModelMixin #### 9)RetrieveUpdateDestoryAPIView 提供 get、put、patch、delete方法 继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
视图代码:
""" 上面的接口代码还可以继续更加的精简,drf在使用GenericAPIView和Mixins进行组合以后,还提供了视图子类。 视图子类是通用视图类 和 模型扩展类 的子类,提供了各种的视图方法调用mixins操作 ListAPIView = GenericAPIView + ListModelMixin 获取多条数据的视图方法 CreateAPIView = GenericAPIView + CreateModelMixin 添加一条数据的视图方法 RetrieveAPIView = GenericAPIView + RetrieveModelMixin 获取一条数据的视图方法 UpdateAPIView = GenericAPIView + UpdateModelMixin 更新一条数据的视图方法 DestroyAPIView = GenericAPIView + DestroyModelMixin 删除一条数据的视图方法 组合视图子类 ListCreateAPIView = ListAPIView + CreateAPIView RetrieveUpdateAPIView = RetrieveAPIView + UpdateAPIView RetrieveDestroyAPIView = RetrieveAPIView + DestroyAPIView RetrieveUpdateDestroyAPIView = RetrieveAPIView + UpdateAPIView + DestroyAPIView """ # from rest_framework.generics import ListAPIView, CreateAPIView, RetrieveAPIView, UpdateAPIView, DestroyAPIView # from rest_framework.generics import ListCreateAPIView, RetrieveAPIView, UpdateAPIView, DestroyAPIView # from rest_framework.generics import ListCreateAPIView, RetrieveUpdateAPIView, DestroyAPIView from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView # class StudentView(ListAPIView, CreateAPIView): class StudentView(ListCreateAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer # class StudentInfoView(RetrieveAPIView, UpdateAPIView, DestroyAPIView): # class StudentInfoView(RetrieveUpdateAPIView, DestroyAPIView): class StudentInfoView(RetrieveUpdateDestroyAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer
序列化器,代码:
from rest_framework import serializers from stuapi.models import Student class StudentModelSerializer(serializers.ModelSerializer): class Meta: model = Student fields = "__all__" extra_kwargs = { "age": { "max_value": 25, "error_messages": { "max_value": "年龄不能超过25岁!", } } }
路由,代码:
from django.urls import path, re_path from . import views urlpatterns = [ # APIView path("students/", views.StudentAPIView.as_view()), re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()), # GenericAPIView path("students2/", views.StudentGenericAPIView.as_view()), re_path("^students2/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()), # GenericAPIView + mixins path("students3/", views.StudentMixinView.as_view()), re_path("^students3/(?P<pk>\d+)/$", views.StudentInfoMixinView.as_view()), # 视图子类 path("students4/", views.StudentView.as_view()), re_path("^students4/(?P<pk>\d+)/$", views.StudentInfoView.as_view()), ]
幻想毫无价值,计划渺如尘埃,目标不可能达到。这一切的一切毫无意义——除非我们付诸行动。