View源码分析:
views文件:
class MyView(View):
def get(self,request):
return HttpResponse('ok')
def post(self,request):
return HttpResponse('post')
urls文件:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$',views.MyView.as_view()),
]
View源码思路分析(这里拿重要的部分源码进行分析):
'''
主要思路:View--》as_view --》as_view下的函数
当有路由匹配进来的时候,就会执行as_view这个方法
'''
class View(object):
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
#继承classmethod
@classonlymethod
'''
这时会把我们在vies创建的MyView类,当作参数传递给as_view这个方法。
相当于as_view(MyView)
**initkwargs是url匹配传递过来的参数:例如 url(r'^$',views.MyView.as_view(age=1)),
'''
def as_view(cls, **initkwargs):
"""
Main entry point for a request-response process.
"""
def view(request, *args, **kwargs):
'''
self = cls(**initkwargs)
这一步是实例化一个对象,将我们传进来的类实例化赋值给self
相当于self=MyView(参数)
'''
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request #将当前的request请求赋值给对象中的request.
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
return view
def dispatch(self, request, *args, **kwargs):
# request: 还是当前的请求对象
if request.method.lower() in self.http_method_names:
'''
获取当前对象(MyView类的对象)的方法的内存地址
例如get请求:handler=getattr(self,'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源码分析:
views文件:
from rest_framework.views import APIView
class MyAPIView(APIView):
def get(self,request):
#此时的request是drf重新封装后的request
print(request._request) #原生request
# 相当于request.GET
data=request.query_params
return HttpResponse('ok')
def post(self,request):
# 相当于request.POST
post_data=request.data
file_data=request.FILES
urls文件
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'apiview/',views.MyAPIView.as_view())
]
APIView源码分析:
'''
#请求来了-》路由匹配上-》view(request)-》调用了self.dispatch()
这时执行的是apiview的dispatch,而不是view的dispatch
'''
class APIView(View):
@classmethod
def as_view(cls, **initkwargs):
if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
def force_evaluation():
raise RuntimeError(
'Do not evaluate the `.queryset` attribute directly, '
'as the result will be cached and reused between requests. '
'Use `.all()` or call `.get_queryset()` instead.'
)
cls.queryset._fetch_all = force_evaluation
'''
view = super().as_view(**initkwargs)
此时的view就View源码的as_view方法下的view
即调用父类(view)的as_view方法。
此时调用的dispatch方法是APIView的dispatch方法,而不是View的
执行顺序是从当前类(MyAPIView)中查找,找不到再从父类(APIView)中查找,再找不到再从APIView的父类View中找
'''
view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
#只要继承了APIView,就不会再进行csrf认证
return csrf_exempt(view)
#APIView的dispatch方法。
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.
"""
self.args = args
self.kwargs = kwargs
'''
()参数中request是当前请求的request
左边的request是重新封装后的request
具体可以参照源码4
'''
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
#三大认证模块(具体看下面源码5)
self.initial(request, *args, **kwargs)
# 这部分跟View类中那部分一样。
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
#源码4、重新封装request的方法
def initialize_request(self, request, *args, **kwargs):
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
#源码5 APIView的initial方法
def initial(self, request, *args, **kwargs):
# 做版本的控制
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
'''
认证组件:校验用户 - 游客、合法用户、非法用户
游客:代表校验通过,直接进入下一步校验(权限校验)
合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
非法用户:代表校验失败,抛出异常,返回403权限异常结果
'''
self.perform_authentication(request)
'''
权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
认证通过:可以进入下一步校验(频率认证)
认证失败:抛出异常,返回403权限异常结果
'''
self.check_permissions(request)
'''
频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
没有达到限次:正常访问接口
达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
'''
self.check_throttles(request)