• REST-framework快速构建API--四部曲


    代码目录结构:

     

    一、使用原生APIView

    使用rest-framework原生的APIView实现过程:

    以url(r'^books/$', views.BookView.as_view(),name="books")为例进行流程分析,

    • 1、views.BookView.as_view()==>APIView的as_view方法==>父类【View】的as_view方法
    • 2、View的as_view方法实际上是返回了View下的view方法
    • 3、view实际上是执行了dispatch方法
    • 4、dispatch执行过程是去找对应的get/post/put/delete/patch方法

    代码实现如下:

    urls文件

    PublishView用于处理publishes的get和post,获取多个资源的情况

    PublishDetailView用于处理publishes/1/的get、put、delete,获取单个资源的情况

    url(r'^publishes/$', views.PublishView.as_view(),name="publish"),
    url(r'^publishes/(?P<pk>d+)/$', views.PublishDetailView.as_view(),name="detailpublish"), 
    

      

    views文件

    使用rest-framework原生的APIView,按照上面说的流程,最后进入dispatch方法,所以只需要我们自己重写get/post/put/delete等方法即可。

    from rest_framework.views import APIView
    # Publish表
    class PublishView(APIView):
        def get(self,request):
      
            publish_list = Publish.objects.all()
            ps = PublishModelSerializers(publish_list, many=True)
            return Response(ps.data)
    
        def post(self,request):
    
            # post请求的数据
            ps = PublishModelSerializers(data=request.data)
            if ps.is_valid():
                print(ps.validated_data)
                ps.save()  # create方法
                return Response(ps.data)
            else:
                return Response(ps.errors)
    class PublishDetailView(APIView):
        def get(self, request, pk):
    
            publish = Publish.objects.filter(pk=pk).first()
            ps = PublishModelSerializers(publish)
            return Response(ps.data)
    
        def put(self, request, pk):
            publish = Publish.objects.filter(pk=pk).first()
            ps = PublishModelSerializers(publish, data=request.data)
            if ps.is_valid():
                ps.save()
                return Response(ps.data)
            else:
                return Response(ps.errors)
    
        def delete(self, request, pk):
            Publish.objects.filter(pk=pk).delete()
    
            return Response()
    

      

    serializer文件

    通过ModelSerializer类,指定model和fields进行序列化操作。

    from rest_framework import serializers
    
    from app01.models import *
    # 为queryset,model对象做序列化
    class PublishSerializers(serializers.Serializer):
        name = serializers.CharField()
        email = serializers.CharField()
    
    
    class PublishModelSerializers(serializers.ModelSerializer):
        class Meta:
            model=Publish
            fields="__all__"
    

      

    原生APIView的缺点

    针对每个model,需要自己写API的各种方法,代码重复程度很高。

    进一步解决办法:使用mixins

    二、使用mixins

    mixins在上一步的基础上进行了进一步的封装,也就是把多资源情况下的GET/POST以及单资源情况下的GET/POST/PUT/DELETE进行了再次封装,只要我们指定集成的类,然后重写对应的方法即可,urls也不用变更。

    from rest_framework import mixins
    from rest_framework import generics
    
    class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
        queryset=Author.objects.all()
        serializer_class =AuthorModelSerializers
    
        def get(self,request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
        def post(self,request, *args, **kwargs):
            return self.create(request, *args, **kwargs)
    
    
    class AuthorDetailView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
        queryset = Author.objects.all()
        serializer_class = AuthorModelSerializers
    
        def get(self,request,*args, **kwargs):
            return self.retrieve(request,*args, **kwargs)
    
        def delete(self,request,*args, **kwargs):
            return self.destroy(request,*args, **kwargs)
    
        def put(self,request,*args, **kwargs):
            return self.retrieve(request,*args, **kwargs)
    

      

    使用mixins还是有代码重复的缺点,每个model表都需要重写这一堆方法和类。

     

    三、使用generics

    使用generics可以很好的避免上面的问题,他直接包含了多资源和单资源情况下的所有方法,而不需要重写get、post、put、delete方法,甚至还包括patch方法。

    from rest_framework import mixins
    from rest_framework import generics
    
    
    class AuthorView(generics.ListCreateAPIView):
        queryset=Author.objects.all()
        serializer_class =AuthorModelSerializers
    
    class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
        queryset = Author.objects.all()
        serializer_class = AuthorModelSerializers
    

      但是这里还有一个缺点,就是单资源和多资源的视图函数以及url都是两份,是不是可以进行一步封装呢?

    四、使用viewsets

    使用viewsets可以通过在as_view中传参进一步简化操作。

    在as_view中传入{动作:方法}的字典给action参数,然后通过getattr和setattr方法进行参数解析,然后通过dispatch中执行对应的方法。

    urls文件

    url(r'^books/$', views.BookViewSet.as_view({"get":"list","post":"create"}),name="book_list"),
        url(r'^books/(?P<pk>d+)$', views.BookViewSet.as_view({
                    'get': 'retrieve',
                    'put': 'update',
                    'patch': 'partial_update',
                    'delete': 'destroy'
                }),name="book_detail"),
    

      

    views文件

    class BookViewSet(viewsets.ModelViewSet):
        queryset = Book.objects.all()
        serializer_class = BookSerializers
    

      

    这就是最终版本,对于一个model表,url两个,一个ModelViewSet类就可以轻易的实现一个API!

    进一步简化

    我们可以看到urls里面看上去是不是很乱的样子,其实,rest-framework也已经解决了这个脏乱差的问题,通过使用routers!

    urls文件修改

    以books为例:

    from django.conf.urls import url,include
    from django.contrib import admin
    from rest_framework import routers
    from app01 import views
    
    
    #router实例化,并将Viewset进行注册
    router = routers.DefaultRouter()
    router.register(r'books',views.BookViewSet)
    
    
    #路由控制
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publishes/$', views.PublishView.as_view(),name="publish"), #  View:view(request)=====APIView:dispatch()
        url(r'^publishes/(?P<pk>d+)/$', views.PublishDetailView.as_view(),name="detailpublish"), #  View:view(request)=====APIView:dispatch()
    
        url(r'',include(router.urls)),
            
    ]
    

      

    其他Viewset需要实例化,同样的操作即可,urls的最终结果为:

    from django.conf.urls import url,include
    from django.contrib import admin
    from rest_framework import routers
    from app01 import views
    
    
    #router实例化,并将Viewset进行注册
    router = routers.DefaultRouter()
    router.register(r'books',views.BookViewSet)
    router.register(r'books',views.PublishViewSet)
    
    
    #路由控制
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'',include(router.urls)),
            
    ]
    

      是不是很简洁?

  • 相关阅读:
    SQL SERVER全面优化
    Mysql常见问题及优化
    Mysql相关问答
    Activiti动态设置办理人扩展
    Activiti流程编辑器针对自定义用户角色表优化改造
    taskService 流程任务组件
    activiti 工作流 动态 设置 指定 节点任务人、责任人、组 的实现方式
    千万级规模高性能、高并发的网络架构经验分享
    B树,B+树,红黑树应用场景AVL树,红黑树,B树,B+树,Trie树
    Mybatis源码分析
  • 原文地址:https://www.cnblogs.com/skyflask/p/10398679.html
Copyright © 2020-2023  润新知