源码分析
cbv
ModelViewSet继承与View (djanog原生View)
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'})
status状态码
为了方便设置状态码,rest framework
在rest_framework.status
模块中提供了常用的状态码常量
- 信息告知-1xx
HTTP_100_CONTINUE = 100
HTTP_101_SWITCHING_PROTOCOLS = 101
HTTP_102_PROCESSING = 102
HTTP_103_EARLY_HINTS = 103
- 成功-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
- 重定向-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
- 客户端报错-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
- 服务器错误-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
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'})
本文来自博客园,作者:ExpiredSaury,转载请注明原文链接:https://www.cnblogs.com/saury/p/16976652.html