django-drf源码解析

    科技2023-10-22  100

    笔记来源课程:https://pythonav.com/index/

    APIView 的特点并且可以通过request获取参数 特点 1.继承自View 2.提供了自己的request对象 3.提供了自己的response对象 4.并且提供了认证,权限,限流等功能 定义序列化器: 1.定义类,继承自Serializer 2.和模型类,字段名字一样 3.和模型类,字段类型一样 4.和模型类,字段选项一样 label 字段说明 read_only = True 只读意思就是只进行序列化不进行反序列化所以反序列化时可以不用传

    反序列化: 校验: 1.字段类型校验 2.字段选项校验 3.单字段校验(方法) 4.多字段校验(方法) 5.自定义校验(方法)

    入库: 1.创建新对象 2.更新对象

    # 安装 pip3 install djangorestframework

    使用注册app

    INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework' ]

    写路由

    from django.conf.urls import url from django.contrib import admin from api import views urlpatterns = [ url(r'^drf/info/', views.DrfInfoView.as_view()), ]

    写视图

    from rest_framework.views import APIView from rest_framework.response import Response class DrfInfoView(APIView): def get(self,request,*args,**kwargs): return Response()

    depth = 1但是这样会拿全部信息 source 在自定义字段时表示来源 自定义字段钩子方法: x1 = serializers.SerializerMethodField() 必须要有此方法 def get_x1(self,obj): obj表示当前对象 return obj.title

    # 当获取文章状态是默认存的是数字,想提取文本可以使用 serializers.CharField(source=get_status_display) required=false表示你在添加数据也就是反序列化的时候不需要填这个数据(只写) read_only = true 表示序列化也就是模型转json的时候使用 # put做全局更新 # patch做局部更新 # 在做局部更新只要在序列化器中传递一个partial=True表示只更新部分

    什么是restful规范

    是一套规则,用于程序之间进行数据交换的约定。 他规定了一些协议,对我们感受最直接的的是,以前写增删改查需要写4个接口,restful规范的就是1个接口,根据method的不同做不同的操作,比如:get/post/delete/put/patch/delete. 初次之外,resetful规范还规定了: 数据传输通过json

    什么是drf

    drf是一个基于django开发的组件,本质是一个django的app。 drf可以办我们快速开发出一个遵循restful规范的程序。

    写程序的潜规则:约束

    # 约束子类中必须实现f1 class Base(object): def f1(self): raise NotImplementedError('asdfasdfasdfasdf') class Foo(Base): def f1(self): print(123) obj = Foo() obj.f1()

    分页(版本一)

    配置 settings.pyREST_FRAMEWORK = { "PAGE_SIZE":2 } 在视图的列表页面 from rest_framework.pagination import PageNumberPagination from rest_framework import serializers class PageArticleSerializer(serializers.ModelSerializer): class Meta: model = models.Article fields = "__all__" class PageArticleView(APIView): def get(self,request,*args,**kwargs): queryset = models.Article.objects.all() # 方式一:仅数据 """ # 分页对象 page_object = PageNumberPagination() # 调用 分页对象.paginate_queryset方法进行分页,得到的结果是分页之后的数据 # result就是分完页的一部分数据 result = page_object.paginate_queryset(queryset,request,self) # 序列化分页之后的数据 ser = PageArticleSerializer(instance=result,many=True) return Response(ser.data) """ # 方式二:数据 + 分页信息 """ page_object = PageNumberPagination() result = page_object.paginate_queryset(queryset, request, self) ser = PageArticleSerializer(instance=result, many=True) return page_object.get_paginated_response(ser.data) """ # 方式三:数据 + 部分分页信息 page_object = PageNumberPagination() result = page_object.paginate_queryset(queryset, request, self) ser = PageArticleSerializer(instance=result, many=True) return Response({'count':page_object.page.paginator.count,'result':ser.data})

    LimitOffsetPagination

    from rest_framework.pagination import PageNumberPagination from rest_framework.pagination import LimitOffsetPagination from rest_framework import serializers class PageArticleSerializer(serializers.ModelSerializer): class Meta: model = models.Article fields = "__all__" class HulaLimitOffsetPagination(LimitOffsetPagination): max_limit = 2 class PageArticleView(APIView): def get(self,request,*args,**kwargs): queryset = models.Article.objects.all() page_object = HulaLimitOffsetPagination() result = page_object.paginate_queryset(queryset, request, self) ser = PageArticleSerializer(instance=result, many=True) return Response(ser.data) url(r'^page/view/article/$', views.PageViewArticleView.as_view()), from rest_framework.generics import ListAPIView class NewFilterBacke(BaseFilterBackend): def filter_queryset(self, request, queryset, view): val = request.query_params.get('cagetory') return queryset.filter(cagetory_id=val) class PageViewArticleSerializer(serializers.ModelSerializer): class Meta: model = models.Article fields = "__all__" class PageViewArticleView(ListAPIView): queryset = "模型数据" filter_backends = [NewFilterBacke, ] # 分类 serializer_class = "序列化器" pagination_class = PageNumberPagination # 分页类 REST_FRAMEWORK = { "PAGE_SIZE":2, "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination" } # get方法 ListAPIView # post方法 CreateAPIView # put方法UpdateAPIView # DestroyAPIView delete方法 # RetrieveAPIView 获取一条数据

    可以重写一些方法

    class TageView(ListAPIView, CreateAPIView): queryset = "数据" serializer_class = "序列化器" # 重写 def get_serializer_class(self): # self.request # self.args # self.kwargs if self.request.method == "GET": return "序列化器" elif self.request.method == 'POST': return "序列化器" def perfiom_create(self,serializer): # 重写添加功能 serializer.save(author=1)

    继承关系:重点

    class View(object): def dispatch(self): print(123) class APIView(View): version_class = None parser_class = None permision_classes = [] def dispatch(self): self.initial() method = getattr(self,"get") return method() def initial(self): self.version_class().xxx # 表示跳出执行方法 self.parser_class() for item in self.permision_classes: item() class GenericAPIView(APIView): queryset = None serilizer_class = None def get_queryset(self): return self.queryset def get_serilizer(self,*args,**kwargs): cls = self.get_serilizer_class() return cls(*args,**kwargs) def get_serilizer_class(self): return self.serilizer_class class ListModelMixin(object): def list(self): queryset = self.get_queryset() ser = self.get_serilizer(queryset,may=True) return Reponse(ser.data) class ListAPIView(ListModelMixin,GenericAPIView): def get(self): return self.list(.....) class Tage(ListAPIView): queryset = models.Users.objects.all() serilizer_class = "序列化器" version_class = URLPathClass parser_class = JSONclass permission_classes = [FOO,Bar] obj = Tage() x = obj.dispatch() # 给用户返回x

    请求的封装

    class HttpRequest(object): def __init__(self): pass @propery def GET(self): pass @propery def POST(self): pass @propery def body(self): pass class Request(object): def __init__(self,request): self._request = request def data(self): if content-type == "application/json" reutrn json.loads(self._request.body.decode('urf-8')) elif content-type == "x-www-...": return self._request.POST def query_params(self): return self._reqeust.GET req = HttpRequest() request = Request(req) request.data request.query_prams request._request.GET request._request.POST request._request.body

    - 视图关系

    class View(object): @classonlymethod def as_view(cls, **initkwargs): def view(request, *args, **kwargs): return self.dispatch(request, *args, **kwargs) return view class APIView(View): @classmethod def as_view(cls, **initkwargs): view = super().as_view(**initkwargs) return csrf_exempt(view) def dispatch(self, request, *args, **kwargs): # 新request内部包含老request(_reuqest=老request) request = self.initialize_request(request, *args, **kwargs) self.request = request self.initial(request, *args, **kwargs) # 通过反射执行“get”方法,并传入新的request handler = getattr(self, request.method.lower()) response = handler(request, *args, **kwargs) # get(requst) return self.response class OrderView(APIView): def get(self,request,*args,**kwargs): return Response('1312')

    版本

    from django.conf.urls import url,include from django.contrib import admin from . import views urlpatterns = [ url(r'^order/$', views.OrderView.as_view()), ] from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request class OrderView(APIView): def get(self,request,*args,**kwargs): print(request.version) print(request.versioning_scheme) return Response('...') def post(self,request,*args,**kwargs): return Response('post')

    源码流程:

    class APIView(View): versioning_class = api_settings.DEFAULT_VERSIONING_CLASS def dispatch(self, request, *args, **kwargs): # ###################### 第一步 ########################### """ request,是django的request,它的内部有:request.GET/request.POST/request.method args,kwargs是在路由中匹配到的参数,如: url(r'^order/(\d+)/(?P<version>\w+)/$', views.OrderView.as_view()), http://www.xxx.com/order/1/v2/ """ self.args = args self.kwargs = kwargs """ request = 生成了一个新的request对象,此对象的内部封装了一些值。 request = Request(request) - 内部封装了 _request = 老的request """ request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: # ###################### 第二步 ########################### self.initial(request, *args, **kwargs) 执行视图函数。。 def initial(self, request, *args, **kwargs): # ############### 2.1 处理drf的版本 ############## version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme ... def determine_version(self, request, *args, **kwargs): if self.versioning_class is None: return (None, None) scheme = self.versioning_class() # obj = XXXXXXXXXXXX() return (scheme.determine_version(request, *args, **kwargs), scheme) class OrderView(APIView): versioning_class = URLPathVersioning def get(self,request,*args,**kwargs): print(request.version) print(request.versioning_scheme) return Response('...') def post(self,request,*args,**kwargs): return Response('post') class URLPathVersioning(BaseVersioning): """ urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'), ] """ invalid_version_message = _('Invalid version in URL path.') def determine_version(self, request, *args, **kwargs): version = kwargs.get(self.version_param, self.default_version) if version is None: version = self.default_version if not self.is_allowed_version(version): raise exceptions.NotFound(self.invalid_version_message) return version

    使用(局部)

    url中写version url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'), from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.versioning import URLPathVersioning class OrderView(APIView): versioning_class = URLPathVersioning def get(self,request,*args,**kwargs): print(request.version) print(request.versioning_scheme) return Response('...') def post(self,request,*args,**kwargs): return Response('post') REST_FRAMEWORK = { "PAGE_SIZE":2,# 每页显示页数 "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination",# 分页 "ALLOWED_VERSIONS":['v1','v2'], # 版本限制 'VERSION_PARAM':'version' # 关键字参数限制 }

    使用(全局)推荐

    url中写version url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'), url(r'^(?P<version>\w+)/users/$', users_list, name='users-list'), 在视图中应用 from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.versioning import URLPathVersioning class OrderView(APIView): def get(self,request,*args,**kwargs): print(request.version) print(request.versioning_scheme) return Response('...') def post(self,request,*args,**kwargs): return Response('post') REST_FRAMEWORK = { "PAGE_SIZE":2, "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination", "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", "ALLOWED_VERSIONS":['v1','v2'], 'VERSION_PARAM':'version' }

    认证

    from django.conf.urls import url,include from django.contrib import admin from . import views urlpatterns = [ url(r'^login/$', views.LoginView.as_view()), url(r'^order/$', views.OrderView.as_view()), url(r'^user/$', views.UserView.as_view()), ] import uuid from django.shortcuts import render from django.views import View from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator from rest_framework.versioning import URLPathVersioning from rest_framework.views import APIView from rest_framework.response import Response from . import models class LoginView(APIView): def post(self,request,*args,**kwargs): user_object = models.UserInfo.objects.filter(**request.data).first() if not user_object: return Response('登录失败') random_string = str(uuid.uuid4()) user_object.token = random_string user_object.save() return Response(random_string) class MyAuthentication: def authenticate(self, request): """ Authenticate the request and return a two-tuple of (user, token). """ token = request.query_params.get('token') user_object = models.UserInfo.objects.filter(token=token).first() if user_object: return (user_object,token) return (None,None) class OrderView(APIView): authentication_classes = [MyAuthentication, ] def get(self,request,*args,**kwargs): print(request.user) print(request.auth) return Response('order') class UserView(APIView): authentication_classes = [MyAuthentication,] def get(self,request,*args,**kwargs): print(request.user) print(request.auth) return Response('user')

    源码分析

    class Request: def __init__(self, request,authenticators=None): self._request = request self.authenticators = authenticators or () @property def user(self): """ Returns the user associated with the current request, as authenticated by the authentication classes provided to the request. """ if not hasattr(self, '_user'): with wrap_attributeerrors(): self._authenticate() return self._user def _authenticate(self): """ Attempt to authenticate the request using each authentication instance in turn. """ for authenticator in self.authenticators: try: user_auth_tuple = authenticator.authenticate(self) except exceptions.APIException: self._not_authenticated() raise if user_auth_tuple is not None: self._authenticator = authenticator self.user, self.auth = user_auth_tuple return self._not_authenticated() @user.setter def user(self, value): """ Sets the user on the current request. This is necessary to maintain compatibility with django.contrib.auth where the user property is set in the login and logout functions. Note that we also set the user on Django's underlying `HttpRequest` instance, ensuring that it is available to any middleware in the stack. """ self._user = value self._request.user = value class APIView(View): authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES def dispatch(self, request, *args, **kwargs): """ `.dispatch()` is pretty much the same as Django's regular dispatch, but with extra hooks for startup, finalize, and exception handling. """ # ###################### 第一步 ########################### """ request,是django的request,它的内部有:request.GET/request.POST/request.method args,kwargs是在路由中匹配到的参数,如: url(r'^order/(\d+)/(?P<version>\w+)/$', views.OrderView.as_view()), http://www.xxx.com/order/1/v2/ """ self.args = args self.kwargs = kwargs """ request = 生成了一个新的request对象,此对象的内部封装了一些值。 request = Request(request) - 内部封装了 _request = 老的request - 内部封装了 authenticators = [MyAuthentication(), ] """ request = self.initialize_request(request, *args, **kwargs) self.request = request def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, parsers=self.get_parsers(), authenticators=self.get_authenticators(), # [MyAuthentication(),] negotiator=self.get_content_negotiator(), parser_context=parser_context ) def get_authenticators(self): """ Instantiates and returns the list of authenticators that this view can use. """ return [ auth() for auth in self.authentication_classes ] class LoginView(APIView): authentication_classes = [] def post(self,request,*args,**kwargs): user_object = models.UserInfo.objects.filter(**request.data).first() if not user_object: return Response('登录失败') random_string = str(uuid.uuid4()) user_object.token = random_string user_object.save() return Response(random_string) class OrderView(APIView): # authentication_classes = [TokenAuthentication, ] def get(self,request,*args,**kwargs): print(request.user) print(request.auth) if request.user: return Response('order') return Response('滚')

    当用户发来请求时,找到认证的所有类并实例化成为对象列表,然后将对象列表封装到新的request对> 象中。 以后在视同中调用request.user 在内部会循环认证的对象列表,并执行每个对象的authenticate方法,该方法用于认证,他会返回两个值分别会赋值给 request.user/request.auth

    权限

    from rest_framework.permissions import BasePermission from rest_framework import exceptions class MyPermission(BasePermission): message = {'code': 10001, 'error': '你没权限'} def has_permission(self, request, view): """ Return `True` if permission is granted, `False` otherwise. """ if request.user: return True # raise exceptions.PermissionDenied({'code': 10001, 'error': '你没权限'}) return False def has_object_permission(self, request, view, obj): """ Return `True` if permission is granted, `False` otherwise. """ return False class OrderView(APIView): permission_classes = [MyPermission,] def get(self,request,*args,**kwargs): return Response('order') class UserView(APIView): permission_classes = [MyPermission, ] def get(self,request,*args,**kwargs): return Response('user') REST_FRAMEWORK = { "PAGE_SIZE":2, "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination", "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", "ALLOWED_VERSIONS":['v1','v2'], 'VERSION_PARAM':'version', "DEFAULT_AUTHENTICATION_CLASSES":["kka.auth.TokenAuthentication",] }

    源码分析

    class APIView(View): permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES def dispatch(self, request, *args, **kwargs): 封装request对象 self.initial(request, *args, **kwargs) 通过反射执行视图中的方法 def initial(self, request, *args, **kwargs): 版本的处理 # 认证 self.perform_authentication(request) # 权限判断 self.check_permissions(request) self.check_throttles(request) def perform_authentication(self, request): request.user def check_permissions(self, request): # [对象,对象,] for permission in self.get_permissions(): if not permission.has_permission(request, self): self.permission_denied(request, message=getattr(permission, 'message', None)) def permission_denied(self, request, message=None): if request.authenticators and not request.successful_authenticator: raise exceptions.NotAuthenticated() raise exceptions.PermissionDenied(detail=message) def get_permissions(self): return [permission() for permission in self.permission_classes] class UserView(APIView): permission_classes = [MyPermission, ] def get(self,request,*args,**kwargs): return Response('user')
    Processed: 0.012, SQL: 8