阅读:48
一、在django中客户端发来的请求会执行视图类的as_view方法,而as_view方法会执行dispatch方法,然后进行反射执行相应的方法(get、post等)
反射:通过字符串的形式操作对象相关的属性
https://www.chenshaowen.com/blog/reflection-of-python.html
1. getattr(object,‘name‘,‘default’)
如果存在name的属性方法,则返回name的属性方法,否则返回default的属性方法。
2. hasattr(object, ’name‘)
判断对象object是否包含名为name的属性方法,存在则返回True,否则返回False。hasattr是通过调用getattr(ojbect, ’name‘)是否抛出异常来实现)。
3. setattr(object,‘name’,’default‘)
设置对象object的name属性值为default,如果没有name属性,那么创建一个新的属性。
4. delattr(object,’name’)
删除对象object的name属性值。
举个栗子
import requests
class Http(object):
def get(self,url):
res = requests.get(url)
response = res.text
return response
def post(self,url):
res = requests.post(url)
response = res.text
return response
# 使用反射后
url = "https://www.jianshu.com/u/14140bf8f6c7"
method = input("请求方法>>>:")
h = Http()
if hasattr(h,method):
func = getattr(h,method)
res = func(url)
print(res)
else:
print("你的请求方式有误...")
https://www.chenshaowen.com/blog/reflection-of-python.html
二、drf中的APIView中只要重写as_view()方法
重写dispatch方法,就能加入相对应的功能,我们来看下drf中APIView中as_view()方法
# 类方法
@classmethod
def as_view(cls, **initkwargs):
"""
Store the original class on the view function.
This allows us to discover information about the view when we do URL
reverse lookups. Used for breadcrumb generation.
"""
# 检查类中定义的queryset是否是这个models.query.QuerySet类型,必行抛异常
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
# 执行父类的as_view方法
view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
# Note: session based authentication is explicitly CSRF validated,
# all other authentication is CSRF exempt.
# 返回view,由于是前后端分离就取消csrf认证
return csrf_exempt(view)
这个方法是APIView里面的,我们可以看到他执行了父类的as_view方法,
也就相当于初始化父类,我们接下来看下最基础django中父类View中的as_view方法是怎么样的
class View:
# 类方法
@classonlymethod
def as_view(cls, **initkwargs):
"""Main entry point for a request-response process."""
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
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)
view.view_class = cls
view.view_initkwargs = initkwargs
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
父类去执行self.dispatch了,上面的执行过程
1、View 的执行顺序:
as_view()方法-----》返回view函数名称(一旦有请求来了就必须要执行as_view方法,然后再执行dispatch方法)
2、APIView 的执行顺序
执行父类as_view方法—》执行dispath方法(APIView重写dispath方法)
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
# 对django原始的request进行封装,返回Request对象(新的对象)。
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
# 这里的request是新封装的request,然后进一步封装,加入新的一些功能,比如认证,限速,权限
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 重写了父类View的dispatch
request = self.initialize_request(request, *args, **kwargs)
我们接下来看看他在原有的request基础上封装了什么
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)
# 这里将原来的request封装进来,加入新的功能
return Request(
request,
parsers=self.get_parsers(),
# 加入认证
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
新的Request他封装了
请求(HttpRequest)。原始请求实例
解析器类(列表/元组)。用于分析
请求内容。
身份验证类(列表/元组)。用于尝试的身份验证
这里我们由于是分析他的认证就不对他封装的其他进行说明,我们还是回到
在APIView中