视图
在上面序列化的组件种已经用到了视图组件,即在视图函数部分进行逻辑操作。
但是很明显的弊端是,对每个表的增删改查加上 单条数据,需要用到 2个类 5个方法(增删改查,单数据查)才可以完整的实现,当表的数量较大的时候,就很蠢了。
因此 rest framework 也对这个进行了多层的封装。
源码位置
rest_framework.viewsets
rest_framework.generics
rest_framework.mixins
最底层的三个基础文件
rest_framework.viewsets
# 内部提供了 as_view 方法 class ViewSetMixin(object): # 此方法提供了 as_view 方法可以加参数的条件 def as_view(cls, actions=None, **initkwargs):... # 用作总的继承类 class GenericViewSet(ViewSetMixin, generics.GenericAPIView): ... # 单数据分支继承类 ,只有全数据和单数据的查看方法 class ReadOnlyModelViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet):... # 全数据分支继承类,最全内置增删改查 以及 单数据查看方法 5个全都有 class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet):...
rest_framework.generics
class GenericAPIView(views.APIView): # queryset 数据对象传入用变量 queryset = None # 在视图中序列化工具对象传入用变量 serializer_class = None # 以下是一些增删改查的各种共功能组合 ,用于继承类使用 class CreateAPIView(mixins.CreateModelMixin, GenericAPIView):
class ListAPIView(mixins.ListModelMixin, GenericAPIView):
class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView):
class DestroyAPIView(mixins.DestroyModelMixin, GenericAPIView):
class UpdateAPIView(mixins.UpdateModelMixin, GenericAPIView):
class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView):
class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericAPIView):
class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericAPIView):
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericAPIView):
rest_framework.mixins
内置的操作方法 增删改查 单行数据查询都在这里
class CreateModelMixin(object): ... class ListModelMixin(object): ... class RetrieveModelMixin(object): ... class UpdateModelMixin(object): ... class DestroyModelMixin(object): ...
彼此继承关系图
基于底层三类进行了两轮封装
GenrericViewSet 封装了 GenericAPIView 和 ViewSetMixin ,于是获得了 传入对象以及 重写 as_view 的功能
ModelViewSet 封装了 GenrericViewSet 和 mixins ,在 GenrericViewSet 的基础上 又获得了 增删改查方法的集成
最初始最全面也是最笨的方式操作表
方式1 2类5方法无判断
对于全部数据的查询以及数据的创建不需要带参数,设计为一条URL
其他单数据的查看编辑和删除在设计一条URL
两条URL 分别对应两个类
全部的内容:
写全了就是 2个类 ,加起来一共5方法
各类中的请求对应方式
class BookView(APIView): def get(self,request): # 对所有数据进行查看 book_list=Book.objects.all() bs=BookModelSerializers(book_list,many=True,context={'request': request}) return Response(bs.data) def post(self,request): # 对数据进行创建提交 # post请求的数据 bs=BookModelSerializers(data=request.data) if bs.is_valid(): print(bs.validated_data) bs.save() # .create()方法 return Response(bs.data) else: return Response(bs.errors) class BookDetailView(APIView): def get(self,request,id): # 对单条数据进行查看 book=Book.objects.filter(pk=id).first() bs=BookModelSerializers(book,context={'request': request}) return Response(bs.data) def put(self,request,id): # 对单条数据进行更新 book=Book.objects.filter(pk=id).first() bs=BookModelSerializers(book,data=request.data) if bs.is_valid(): bs.save() # .updata() return Response(bs.data) else: return Response(bs.errors) def delete(self,request,id): # 删除数据 Book.objects.filter(pk=id).delete() return Response()
方式2 一类5方法带判断
只写一个类,内含5方法,在get 的时候进行一次判断即可
class IndexView(views.APIView): def get(self,request,*args,**kwargs): pk = kwargs.get('pk') if pk: pass # 获取单条信息 else: pass # 获取列表信息 def post(self,request,*args,**kwargs): pass def put(self,request,*args,**kwargs): pass def patch(self,request,*args,**kwargs): pass def delete(self,request,*args,**kwargs): pass
class SchoolView(APIView): def get(self, request, *args, **kwargs): query_set = models.School.objects.all() ser_obj = app01_serializers.SchoolSerializer(query_set, many=True) return Response(ser_obj.data) class SchoolDetail(APIView): def get(self, request, pk, *args, **kwargs): obj = models.School.objects.filter(pk=pk).first() ser_obj = app01_serializers.SchoolSerializer(obj) return Response(ser_obj.data)
第一次整合
利用GenericeAPIView 传入 queryset对象以及 序列化对象, 再利用内置的 mixins 中的操作方法省去操作代码
from rest_framework.generics import GenericAPIView from rest_framework import.mixins class SchoolView(GenericAPIView, mixins.ListModelMixin): queryset = models.School.objects.all() serializer_class = app01_serializers.SchoolSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) class SchoolDetail(GenericAPIView, mixins.RetrieveModelMixin, mixins.CreateModelMixin): queryset = models.School.objects.all() serializer_class = app01_serializers.SchoolSerializer def get(self, request, pk, *args, **kwargs): return self.retrieve(request, pk, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs)
路由依旧是分成两条,单数据和多数据分开
url(r'school/$', views.SchoolView.as_view()), url(r'school/(?P<pk>d+)/$', views.SchoolDetail.as_view()),
第二次整合
利用GenericeAPIView 传入 queryset对象以及 序列化对象, 再利用内置的 generics 中的操作方法省去操作代码
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView class SchoolView(ListCreateAPIView): queryset = models.School.objects.all() serializer_class = app01_serializers.SchoolSerializer class SchoolDetail(RetrieveUpdateDestroyAPIView): queryset = models.School.objects.all() serializer_class = app01_serializers.SchoolSerializer
路由依旧是分成两条,单数据和多数据分开,同第一次整合无区别
url(r'school/$', views.SchoolView.as_view()),
url(r'school/(?P<pk>d+)/$', views.SchoolDetail.as_view()),
终极版
直接继承最终的 ModelViewSet 继承类 ,ModelViewSet 在 ViewSetMixin 类 之上,可以重写 as_view 方法能够添加参数
from rest_framework.viewset import ModelViewSet class SchoolView(ModelViewSet): queryset = models.School.objects.all() serializer_class = app01_serializers.SchoolSerializer
因为视图被极大的压缩,参数的传递交给了 as_view 来处理,因此 url 会变得比以往复杂,url 还可以进一步封装,详情往下看路由部分
url(r'school/$', views.SchoolView.as_view({ "get": "list", "post": "create", })), url(r'school/(?P<pk>d+)/$', views.SchoolView.as_view({ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' })),
终极版自定制
class P2(PageNumberPagination): page_size = 3 #每一页显示的条数 page_query_param = 'page' #获取参数中传入的页码 page_size_query_param = 'size' #获取url参数中每页显示的数据条数 max_page_size = 5 class IndexSerializer(ModelSerializer): class Meta: model = models.UserInfo fields = "__all__" class IndexView4(ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = IndexSerializer pagination_class = P2 def list(self, request, *args, **kwargs): '''获取get请求的所有''' pass def retrieve(self, request, *args, **kwargs): '''查看单条数据''' pass def destroy(self, request, *args, **kwargs): '''删除DELETE''' pass def create(self, request, *args, **kwargs): '''添加数据POST''' pass def update(self, request, *args, **kwargs): '''全部修改PUT''' pass def partial_update(self, request, *args, **kwargs): '''局部修改PATCH''' pass
二次整理版本( 浓缩版 )
""" 继承结构 (功能↓) (封装↑) ModelViewSet/ReadOnlyModelViewSet generics.xxx GenericViewSet mixins.xxx GenericAPIView APIView ViewSetMixin 基础的四个功能组件(每个都有自己独有功能) APIView(View) 啥都没有, 全部手写去吧 ViewSetMixin(object) 提供了 as_view 的重写 以及 initialize_request 里面很多的 action mixins.xxx(object) 提供以下的 5 个基础的增删改查方法, CreateModelMixin - create() post() ListModelMixin - list() get() RetrieveModelMixin - retrieve() patch() DestroyModelMixin - destroy() delete() UpdateModelMixin - update() put() GenericAPIView(views.APIView) 提供了以下字段的封装, 不需要手写了 queryset = None 数据库对象 serializer_class = None 序列化对象 lookup_field = 'pk' 默认查询字段, 默认是 id lookup_url_kwarg = None 查询单一数据时URL中的参数关键字名称, 默认与look_field相同 filter_backends = api_settings.DEFAULT_FILTER_BACKENDS 过滤 pagination_class = api_settings.DEFAULT_PAGINATION_CLASS 分页器选择 进阶的两个(对基础组件的一层封装) GenericViewSet(ViewSetMixin, generics.GenericAPIView) 集合了 as_view 以及 可写参数 generics.xxxx.....(mixins.xxxxx,GenericAPIView) 各式的组合增删改查, 以及附加参数功能 CreateAPIView(mixins.CreateModelMixin,GenericAPIView) ListAPIView(mixins.ListModelMixin,GenericAPIView) RetrieveAPIView(mixins.RetrieveModelMixin,GenericAPIView) DestroyAPIView(mixins.DestroyModelMixin,GenericAPIView) UpdateAPIView(mixins.UpdateModelMixin,GenericAPIView) ListCreateAPIView(mixins.ListModelMixin,mixins.CreateModelMixin,GenericAPIView) RetrieveUpdateAPIView(mixins.RetrieveModelMixin,mixins.UpdateModelMixin,GenericAPIView) RetrieveDestroyAPIView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,GenericAPIView) RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,GenericAPIView) 终极的两个(二级封装更加方便了) ReadOnlyModelViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet) 其他都有, 只能读取 ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet) 全部都有, 集合了所有的请求方式 视图继承的选择 一阶段 View 你这是在用 django 二阶段 APIView 在用 drf 了.但是是最基础的方式 三阶段 GenericAPIView 很多参数可以用了, 但是所有方法自己写 四阶段 GenericAPIView + mixins 能用参数了, 不用写各请求的逻辑了. 但是还要写个壳子 五阶段 GenericAPIView + generics.xxx 能用参数, 而且灵活组合自己的请求类型, 壳子也不用写了 六阶段 GenericViewSet + generics.xxx 能用参数, 灵活组请求类型, 重写了as_view, 获得高级路由功能 七阶段 ReadOnlyModelViewSet 前面有的我都有. 但是我只能读 八阶段 ModelViewSet 我全都有 """
路由
完全自定义路由
单数据,全数据的两只路由加 带格式的两只路由一共4条路由
# http://127.0.0.1:8000/api/v1/auth/ url(r'^auth/$', views.AuthView.as_view()),
# http://127.0.0.1:8000/api/v1/auth.json # 想要让页面显示json格式 url(r'^auth.(?P<format>[a-z0-9]+)$', views.AuthView.as_view()),
# http://127.0.0.1:8000/api/v1/auth/1/ url(r'^auth/(?P<pk>d+)/$', views.AuthView.as_view()),
# http://127.0.0.1:8000/api/v1/auth/1.json url(r'^auth/(?P<pk>d+).(?P<format>[a-z0-9]+)$', views.AuthView.as_view()),
class AuthView(views.APIView): def get(self,request,*args,**kwargs): return Response('...')
半自动路由
重写了 as_view 方法后,可以在as_view方法中加入参数传递方法对应,手动指定响应方式和视图方法的映射
url(r'^index/$', views.IndexView.as_view({'get':'list','post':'create'})), url(r'^index.(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'list','post':'create'})), url(r'^index/(?P<pk>d+)/$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})), url(r'^index(?P<pk>d+).(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})), class IndexView(viewsets.ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = IndexSerializer pagination_class = P2
全自动路由
完全自动生成所有的 url,且自动创建了视图关系
# 注册前的准备,做一个实例化对象 routers=routers.DefaultRouter() # 注册需要加两个参数 ("url前缀",视图函数) routers.register("authors",views.AuthorModelView) routers.register("books",views.AuthorModelView)
""" 会自动帮你生成 4 条 url ^authors/$ [name='author-list'] ^authors.(?P<format>[a-z0-9]+)/?$ [name='author-list'] ^authors/(?P<pk>[^/.]+)/$ [name='author-detail'] ^authors/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='author-detail'] # 响应器控制 """ urlpatterns = [ # url(r'^authors/$', views.AuthorModelView.as_view({"get":"list","post":"create"}),name="author"), # url(r'^authors/(?P<pk>d+)/$', views.AuthorModelView.as_view({"get":"retrieve","put":"update","delete":"destroy"}),name="detailauthor"), # 上面的两条被简化成了下面一句话 url(r'', include(routers.urls)), ]
router = DefaultRouter() router.register('index',views.IndexViewSet) urlpatterns = [ url(r'^', include(router.urls)), ] class IndexViewSet(viewsets.ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = IndexSerializer pagination_class = P2 class IndexSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__"