源码分析

cbv

ModelViewSet继承与View (djanog原生View)

image-20221130191945881

path('books/',views.Books.as_view())#在这个地方应该写函数内存地址,views.Books.as_view()执行完,是个函数内存地址,as_view是一个类方法,类直接来调用,会把类自动传入
放入了一个view的内存地址,(View--》as_view--》内层函数)

class Books(View):
    # 只能接收get请求
    http_method_names = ['get']
    def get(self, request):
        print(self.request)
        return HttpResponse('ok')
    def post(self,request):
        print(request.POST)
- 视图类里边必须继承View,,
- 在类里写get方法,post方法,只要get请求来了,就走get方法, 跟之前fbv写法完全一样。
- 路由:views.Books.as_view()-------->放入了一个view的内存地址,
- 请求一旦来了,路由匹配上----》view(request)---》self.dispatch(request,*args, **kwargs)
-dispatch---》把请求方法转成小写,----》通过反射,去对象中找,没有get方法,有就加括号执行,并且把request传进去


"""源码分析"""

#请求来了,如果路径匹配,会执行,函数内存地址(request)
def view(request, *args, **kwargs):
    #request是当次请求的request
    self = cls(**initkwargs)
    self.setup(request, *args, **kwargs)
    if not hasattr(self, 'request'): #实例化得到一个对象 Book对象
        raise AttributeError(
            "%s instance has no 'request' attribute. Did you override "
            "setup() and forget to call super()?" % cls.__name__
        )
        return self.dispatch(request, *args, **kwargs)
    
    
    
    
def dispatch(self, request, *args, **kwargs):
    #request就是当次请求的request  selef是Book对象
    if request.method.lower() in self.http_method_names:
        #handle是自己写的Book类的get方法的内存地址
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs) #执行get(request)   

APIView源码分析(drf提供,扩展了View功能)

- 视图类里边必须继承APIView,,
- 在类里写get方法,post方法,只要get请求来了,就走get方法, 跟之前fbv写法完全一样。
- 路由:views.Books.as_view()-------->放入了一个view的内存地址,处理了csrf,所有请求都没有csrf校验了
- 请求一旦来了,路由匹配上----》view(request)---》self.dispatch(request,*args, **kwargs),现在这个dispatch不是View中的dispatch,而是APIView中的dispatch
-dispatch---》把请求方法转成小写,----》通过反射,去对象中找,没有get方法,有就加括号执行,并且把request传进去






#urls.py
path('booksapiview/', views.BooksAPIView.as_view()),在这个地方应该写函数内存地址

#views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request

class BooksAPIView(APIView):
    def get(self, request):
        #request已经不是原生的django的request了,是drf自己定义的request对象
        print(self.request)
        return HttpResponse('ok')
    
"""源码分析"""

#APIView的as_view方法(类的绑定方法)
@classmethod
def as_view(cls, **initkwargs):
    view = super().as_view(**initkwargs)#调用父类(View)的as_view方法,
    view.cls = cls
    view.initkwargs = initkwargs
    #以后所有的请求都没有csrf认证了,只要继承了APIV i额外,就没有csrf认证了
    return csrf_exempt(view)

#请求来了,路由匹配上,会执行view(request),调用了self.dispatch(),会执行apiview的self.dispatch()

#APIView的dispatch方法
 def dispatch(self, request, *args, **kwargs):

        self.args = args
        self.kwargs = kwargs
        #请求模块(解析模块)
        # self.initialize_request(request, *args, **kwargs)   这里的request是当次请求的request
        #request= self.initialize_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)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
			#响应模块
            response = handler(request, *args, **kwargs)

        except Exception as exc:
            #异常模块
            response = self.handle_exception(exc)
		#渲染模块
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

    
#APIView的initial方法源码分析
    def initial(self, request, *args, **kwargs):
       	#认证组件:校验用户,游客,合法用户,非法用户
        #游客:代表校验通过,直接进入下一步校验(权限校验)
        #合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
        #非法用户:代表校验失败,抛出异常,返回403权限异常结果
        self.perform_authentication(request)
        #权限组件:校验用户权限-必须登录,所有用户、登录读写游客只读,自定义用户角色
        #认证通过:可以进入下一步校验(频率认证)
        #认证失败:抛出异常,返回403权限异常结果
        self.check_permissions(request)
        #频率权限:限制视图接口被访问的频率次数-限制的条件(IP,id,唯一键)、频率周期时间(s、m、h)、频率次数(3/s)
        #没有达到限次:正常访问接口
        #达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
        self.check_throttles(request)

补充:

一切皆对象

def foo(a, b):
    return a + b

foo.name = 'zhao'

print(foo(1, 3))
print(foo.name)

局部禁用csrf

#视图函数中加装饰器@csrf_exempt

#csrf_exempt(view)和在视图函数上加装饰器是一摸一样的
from django.views.decorators.csrf import csrf_exempt

urlpatterns = [
    path('test/',csrf_exempt(views.test))#也是禁用csrf认证
]

drf的Request类

from rest_framework.request import Request
#只要继承了APIView,视图中的request对象,都是新的,也就是上面这个request的对象,

#老的request在新的request._request里

#以后使用request对象,就像使用之前的request是一摸一样的(因为重写了__getattr__方法)

 def __getattr__(self, attr):
        try:
            return getattr(self._request, attr) #通过反射,取原生的request对象,取出属性和方法
        except AttributeError:
            return self.__getattribute__(attr)
        
        
# request.data 感觉是数据属性,其实是个方法,@property修饰了,,它是一个字段,前端以三种编码格式传入的数据,都在request.data中
# 请求对象.query_params 与django标准的request.GET相同,只是更换了更正确的名称而已



#get请求传过来的数据,从哪取?
	request.GET
 

"""源码分析"""
******************************************
    @property
    def query_params(self):
        """
        More semantically correct name for request.GET.
        """
        return self._request.GET
******************************************    
	
    #views.py
    class BooksAPIView(APIView):
    def get(self, request):
        print(self.request)
        print(request.query_params)#get请求,地址中的参数
		#原来获取get请求,用的是request.GET
        print(request.GET)

        return HttpResponse('ok')

#文件 FILES
"""源码分析"""
****************************************** 
    @property
    def FILES(self):
        # Leave this one alone for backwards compat with Django's request.FILES
        # Different from the other two cases, which are not valid property
        # names on the WSGIRequest class.
        if not _hasattr(self, '_files'):
            self._load_data_and_files()
        return self._files
****************************************** 

drf的Response类

#from rest_framework.response import Response

class Response(SimpleTemplateResponse):
    def __init__(self, data=None, status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None):

# data:要返回的数据,字典
#status:返回的状态码,默认是200
#template_name 渲染的模板的名字,(自定制的模板)
#headers:响应头,可以往响应头中放东西,就是一个字典
#content_type:响应的编码格式 'application/json'  和 'text/html'

#urls.py
   path('test/',views.TestView.as_view()),

#views.py
class TestView(APIView):
    def get(self, request):
        print(request)
        return Response({'name': 'zhao'}, status=301, headers={'token': 'test'})

image-20221203202936839

status状态码

为了方便设置状态码,rest frameworkrest_framework.status模块中提供了常用的状态码常量

  1. 信息告知-1xx
HTTP_100_CONTINUE = 100
HTTP_101_SWITCHING_PROTOCOLS = 101
HTTP_102_PROCESSING = 102
HTTP_103_EARLY_HINTS = 103
  1. 成功-2xx
HTTP_200_OK = 200
HTTP_201_CREATED = 201
HTTP_202_ACCEPTED = 202
HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203
HTTP_204_NO_CONTENT = 204
HTTP_205_RESET_CONTENT = 205
HTTP_206_PARTIAL_CONTENT = 206
HTTP_207_MULTI_STATUS = 207
HTTP_208_ALREADY_REPORTED = 208
HTTP_226_IM_USED = 226
  1. 重定向-3xx
HTTP_300_MULTIPLE_CHOICES = 300
HTTP_301_MOVED_PERMANENTLY = 301
HTTP_302_FOUND = 302
HTTP_303_SEE_OTHER = 303
HTTP_304_NOT_MODIFIED = 304
HTTP_305_USE_PROXY = 305
HTTP_306_RESERVED = 306
HTTP_307_TEMPORARY_REDIRECT = 307
HTTP_308_PERMANENT_REDIRECT = 308
  1. 客户端报错-4xx


HTTP_400_BAD_REQUEST = 400
HTTP_401_UNAUTHORIZED = 401
HTTP_402_PAYMENT_REQUIRED = 402
HTTP_403_FORBIDDEN = 403
HTTP_404_NOT_FOUND = 404
HTTP_405_METHOD_NOT_ALLOWED = 405
HTTP_406_NOT_ACCEPTABLE = 406
HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407
HTTP_408_REQUEST_TIMEOUT = 408
HTTP_409_CONFLICT = 409
HTTP_410_GONE = 410
HTTP_411_LENGTH_REQUIRED = 411
HTTP_412_PRECONDITION_FAILED = 412
HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413
HTTP_414_REQUEST_URI_TOO_LONG = 414
HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416
HTTP_417_EXPECTATION_FAILED = 417
HTTP_418_IM_A_TEAPOT = 418
HTTP_421_MISDIRECTED_REQUEST = 421
HTTP_422_UNPROCESSABLE_ENTITY = 422
HTTP_423_LOCKED = 423
HTTP_424_FAILED_DEPENDENCY = 424
HTTP_425_TOO_EARLY = 425
HTTP_426_UPGRADE_REQUIRED = 426
HTTP_428_PRECONDITION_REQUIRED = 428
HTTP_429_TOO_MANY_REQUESTS = 429
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451
  1. 服务器错误-5xx
HTTP_500_INTERNAL_SERVER_ERROR = 500
HTTP_501_NOT_IMPLEMENTED = 501
HTTP_502_BAD_GATEWAY = 502
HTTP_503_SERVICE_UNAVAILABLE = 503
HTTP_504_GATEWAY_TIMEOUT = 504
HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505
HTTP_506_VARIANT_ALSO_NEGOTIATES = 506
HTTP_507_INSUFFICIENT_STORAGE = 507
HTTP_508_LOOP_DETECTED = 508
HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509
HTTP_510_NOT_EXTENDED = 510
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511

image-20221208100105613

from rest_framework import status

class TestView(APIView):
    def get(self, request):
        print(request)
        return Response({'name': 'zhao'}, status=status.HTTP_200_OK, headers={'token': 'test'})
posted @ 2022-12-12 17:19  ExpiredSaury  阅读(24)  评论(0编辑  收藏  举报