TOP

rest framework 视图,路由

 视图

  在上面序列化的组件种已经用到了视图组件,即在视图函数部分进行逻辑操作。

  但是很明显的弊端是,对每个表的增删改查加上 单条数据,需要用到 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__"

 

posted @ 2019-01-15 18:42  羊驼之歌  阅读(380)  评论(0编辑  收藏  举报