zoukankan      html  css  js  c++  java
  • django restframework

    APIView

    1.restframework的APIView源码剖析

    类的继承: 继承了原生View类并继承了as_view方法

    方法重写:重写了dispatch方法

    2.APIView的使用

    pip install djangorestframework #下载djangorestframework

            from rest_framework.views import APIView
    class LoginView(APIView):
    def get(self, request):
       pass

    解析器组件

    1.使用示例
    class LoginView(APIView):
    def get(self, request):
       pass
       def post(self, request):
           request.data  # 新的request对象 @property
           return
    2.部分重要关键源码
    class APIView(View):
    @classmethod
    def as_view(cls, **initkwargs):
       pass
    super(APIView, cls).as_view(**initkwargs)

    def initialize_request(self, request, *args, **kwargs):

    from rest_framework.request import Request

    return Request(
    request,  # 原生request对象
    parsers=self.get_parsers(), #
    authenticators=self.get_authenticators(),
    negotiator=self.get_content_negotiator(),
    parser_context=parser_context
    )

    def dispatch(self):
       pass
    request = self.initialize_request(request, *args, **kwargs)
       self.request = request

    def get_parsers(self):

    return [parser() for parser in self.parser_classes]
    3.实现流程
    1. views.LoginView.as_view()

    2. LoginView里面没有as_view方法,到父类APIView去找

    3. 执行View里面的as_view()方法,返回view函数 def view(request, *args, kwargs): ​ self = cls(initkwargs) ​ if hasattr(self, 'get') and not hasattr(self, 'head'): ​ self.head = self.get ​ self.request = request ​ self.args = args ​ self.kwargs = kwargs ​ return self.dispatch(request, *args, **kwargs)

    4. url和视图函数之间的绑定关系建立完毕 { "login": view},等待用户请求

    5. 接收到用户请求:login,到建立好的绑定关系里面执行对应的视图函数:view(request)

    6. 视图函数的执行结果是什么就返回给用户什么:self.dispatch(), self.dispatch()的执行结果是什么,就返回给用户什么

    7. 此时的self代表的是LoginView的实例化对象

    8. 开始找dispatch方法,self里面没有,LoginView里面也没有,在APIView里面有

    9. 开始执行APIView里面的dispatch

    10. 最后找到http方法(GET,POST,PUT,DELETE),根据请求类型查找(request.method.lower())

    11. 开始执行找到的方法(GET),self.get(), self此时代表LoginView的实例化对象 11.1 假设接收到的是POST请求, 执行request.data 11.2 根据分析,所有的解析工作都在request.data里面实现,且data是一个方法(被装饰后的) 11.2 开始执行request.data @property def data(self): if not hasattr(self, 'full_data'): self.load_data_and_files() return self.full_data 11.3 执行self.load_data_and_files 11.4 执行self.data, self.files = self.parse() 11.5 parser = self.negotiator.select_parser(self, self.parsers) 11.5.1 开始找self.parsers 11.5.2 self.get_parses() [ parse() for parse in self.parser_classes ] 11.5.3 parser_classes = api_settings.DEFAULT_PARSER_CLASSES 11.5.4 from rest_framework import api_settings 11.5.5 api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) 11.5.6 class APISettings():pass

      ​ 11.5.7 找不到DEFAULT_PARSER_CLASSES,getattr 'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ),

      11.5.8 首先找程序的settings

      11.5.9 然后找rest_framework的settings

      11.6 self.data就是我们想要的数据 11.7 DRF将self.data = data 11.8 request.data

    12. 在LoginView里面找到了对应的方法,执行该方法,最后返回给用户

      • DRF的所有功能都是在as_view()和dispatch里面重写的

      • 而解析器组件在dispatch方法里面重写了,具体是在重新封装的Request对象里面

    序列化组件

    1.通过序列化组件进行get接口设计

    GET 127.0.0.1:8000/books/ # 获取所有数据,返回值: [{}, {}]

    GET 127.0.0.1:8000/books/{id} # 获取一条数据,返回值:{}

    POST 127.0.0.1:8000/books/ # 新增一条数据,返回值:{}

    PUT 127.0.0.1:8000/books/{id} # 修改数据,返回值:{}

    DELETE 127.0.0.1:8000/books/{id} # 删除数据,返回空

    导入模块:from rest_framework import serializers

    建立一个序列化类:

     class BookSerializer(serializers.Serializer):
    publish_name = serializers.CharField(read_only=True, source="publish.name")
    authors_list = serializers.SerializerMethodField()

    def get_authors_list(self, book_obj):
    pass

    开始序列化:

    class BookView(APIView):
       def get(self, request):
           origin_data = Book.objects.all() #获取queryset
           serialized_data = BookSerializer(origin_data, many=True) #开始序列化
           #book_obj = Book.objects.all()
           #serialized_data = BookSerializer(book_obj, many=False) get单条数据接口设计
           return Response(serialized_data.data) #获取序列化后的数据,返回给客户端

     

    2.post接口设计
    def post(self, request):
    verified_data = BookSerializer(data=request.data)
    if verified_data.is_valid():
    book = verified_data.save()
    authors=Author.objects.filter(nid__in=request.data
    ['authors'])
    book.authors.add(*authors)
    return Response(verified_data.data)
    else:
    return Response(verified_data.errors)

    3.put接口设计
    def put(self, request, nid):
    book_obj = Book.objects.get(pk=nid)
    verified_data = BookSerializer(data=request.data, instance=book_obj)
    if verified_data.is_valid():
    verified_data.save()
    return Response(verified_data.data)
    else:
    return Response(verified_data.errors)

    视图组件

    1. 使用视图组件的mixin进行接口逻辑优化
    a.导入mixin
    from rest_framework.mixinx import (

    ListModelMix,

    CreateModelMixin,

    DestroyModelMixin,

    UpdateModelMixin,

    RetrieveModelMixin

    )

    from rest_framework.generics import GenericAPIView

     

    b.定义序列化类
    class BookSerializer(serializers.ModelSerializer):
       class Meata:
           model = Book
           fields = ('field_name', )
           extra_kwargs = {"publish": {"write_only": True}, }

           publish_name = serializers.CharField(read_only=True, source="publish.name")
           authors = serializers.SerializerMethodField()

           def get_authors(self, book_obj):
               pass
    c.导入序列化类

    from .app_serializers import BookSerializer

    d.定义视图类
    class BookView(ListModelMix, CreateModelMixin, GenericAPIView):
     #queryset和serializer_class是固定的写法
         queryset = Book.objects.all()
         serializer_class = BookSerializer

         def get():
           return self.list()

         def post():
           return self.create()


    class BookFilterView(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
       queryset = Book.objects.all()
    serializer_class = BookSerializer
    def get():
       return self.retrieve()

    def delete():
       return self.destroy()

    def put():
       return self.update()
     
    #注意:单条数据操作的url是这样的:re_path(r'books/(?P<pk>d+)/$, views.BookFilterView.as_view())



    2.使用视图组件的view进行接口逻辑优化
    a.导入模块
    from rest_framework import generics
    b.写视图类
    class BookView(generics.ListCreateAPIView)
       queryset = Book.objects.all()
       serializer_class = BookSerializer

    class BookFilterView(generics.RetrieveUpdateDestroyAPIView):
       queryset = Book.objects.all()
       serializer_class = BookSerializer
    3.使用视图组件的viewset进行接口逻辑优化
    a.导入模块
    from rest_framework.viewsets import ModelViewSet
    b.设计url
    re_path(r'books/$', views.BookView.as_view({
       'get': 'list',
       'post': 'create'
    })),
    re_path(r'books/(?P<pk>d+)/$', views.BookView.as_view({
       'get': 'retrieve',
       'delete': 'destroy',
       'put': 'update'
    }))
    c.设计视图类
    class BookView(ModelViewSet):
       queryset = Book.objects.all()
       serializer_class = BookSerializer

     

    认证组件

    1.使用方法
    a.定义认证类
    class UserAuth():
       def authenticate_header(self, request):
           pass

       def authenticate(self, request):
           pass
    b.在需要认证的数据接口里面指定认证类
    class BookView(ModelViewSet):
       authentication_classes = [UserAuth]
       queryset = Book.objects.all()
       serializer_class = BookSerializer
    2.全局认证

    在settings文件里面指定:

     REST_FRAMEWORK = {
    "DEFAULT_PARSER_CLASSES": (JsonParser, FormParser),
    "DEFAULT_AUTHENTICATION_CLASSES": ("serializer.utils.app_authes.UserAuth",)
    }
    3.源码剖析
    - self.dispatch() # self BookView的实例化对象
    - self.initial() # self BookView的实例化对象
    - self.perform_authentication()  # self BookView的实例化对象
    - request.user    # self Request的实例化对象
    - self._authenticate() # self Request的实例化对象
    self.user = xxx

     

    权限组件

    1.权限组件的使用
    a.定义一个权限类
        class UserPerm():
           def has_permission(self, request, view):
               if 有权限:
                   return True
               else:
                   return False
    b.指定权限类
    class BookView(APIView):
       permission_classes = [UserPerm]

     

    频率组件

    1.频率组件的使用
    a.定义一个频率类
    class RateThrottle():
       def allow_request(request, self):
           if 没有超过限制:
          return True
           else:
          return False

       def wait(self):
      return 10
    b.指定频率类
    class BookView(APIView):
    throttle_classes = [RateThrottle]
    2.使用DRF的简单频率控制来控制用户访问频率(局部)
            -导入模块
    from rest_framework.throttling import SimpleRateThrottle
    - 定义并继承SimpleRateThrottle
       class RateThrottle(SimpleRateThrottle):
       # 指定访问频率
       rate = '5/m'

    # 指定通过什么方式来区分用户
    def get_cache_key(self, request, view):
       return self.get_ident(request)

    - 指定频率类
       class BookView(APIView):
       throttle_classes = [RateThrottle]
    3.使用DRF的简单频率控制来控制用户访问频率(全局)
        -导入模块
    from rest_framework.throttling import SimpleRateThrottle

    - 定义并继承SimpleRateThrottle
       class RateThrottle(SimpleRateThrottle):
       # 指定访问频率
       scope = 'visit_rate'

    # 指定通过什么方式来区分用户
    def get_cache_key(self, request, view):
       return self.get_ident(request)

    - 在settings里面指定频率类和访问频率
    REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_CLASSES": ('serializer.utils.app_throttles.RateThrottle',),
    "DEFAULT_THROTTLE_RATES": {
    "visit_rate": "5/m"
    }
    }

     

    url注册器组件

    1.url注册器组件的使用
    a.导入模块
    from django.urls import re_path, include        
    from .serializer import views
    from rest_framework import routers
    b.生成一个注册器示例对象
    router = routers.DefaultRouter()

     

    c.将需要自动生成url的接口注册
    router.register(r"books", views.BookView)

     

    d.开始自动生成url
    urlpatterns = [
       re_path('^', include(router.urls)),
    ]

     

    分页器组件

    1.使用方法​
        - 导入模块
      from rest_framework.pagination import PageNumberPagination
       
    - 获取数据
       books = Book.objects.all()

    - 创建一个分页器对象
       paginater = PageNumberPagination()

    - 开始分页
    paged_books = paginater.paginate_queryset(books, request)

    - 开始序列化
       serialized_books = BookSerializer(paged_books, many=True)

    - 返回数据
       return Response(serialized_books.data)
    2.局部实现
        - 导入模块
      from rest_framework.pagination import PageNumberPagination
     
    - 自定义一个分页类并集成PageNumberPagination
    class MyPagination(PageNumberPagination):
       page_size = 2
    page_query_param = 'p'
    page_size_query_param = 'size'
    max_page_size = 5

    - 实例化一个分页类对象
    paginater = MyPagination()

    - 开始分页
    paged_books = paginater.paginate_queryset(books, request)

    - 开始序列化
       serialized_books = BookSerializer(paged_books, many=True)

    - 返回数据
       return Response(serialized_books.data)

    响应器组件

    a.导入模块
     from rest_framework.renderers import JsonRender

     

    b.指定返回类
      class BookView(APIView):
           render_classes = [JsonRender]

     

  • 相关阅读:
    【LeetCode】205. Isomorphic Strings
    Syscall param open(filename) points to unaddressable byte(s)
    五种主要多核并行编程方法分析与比较
    计算机时间复杂度和空间复杂度
    CUDA学习笔记(二)【转】
    CUDA学习笔记(一)【转】
    CUDA Thread Indexing
    Intel MKL函数,如何得到相同的计算结果?【转】
    CUDA编程
    GPU(CUDA)学习日记(十一)------ 深入理解CUDA线程层次以及关于设置线程数的思考
  • 原文地址:https://www.cnblogs.com/luxiangyu111/p/10099390.html
Copyright © 2011-2022 走看看