Django源码分析 路由、视图(二)

上一篇大致分析了路由的解析过程,下面开始分析视图相关的代码

接着看django.core.handlers.base.BaseHandler._get_response这个方法

class BaseHandler:

    def make_view_atomic(self, view):
        non_atomic_requests = getattr(view, '_non_atomic_requests', set())
        for db in connections.all():
            if db.settings_dict['ATOMIC_REQUESTS'] and db.alias not in non_atomic_requests:
                view = transaction.atomic(using=db.alias)(view)
        return view

    def _get_response(self, request):
        """
        Resolve and call the view, then apply view, exception, and
        template_response middleware. This method is everything that happens
        inside the request/response middleware.
        """
        response = None

        if hasattr(request, 'urlconf'):
            urlconf = request.urlconf
            set_urlconf(urlconf)
            resolver = get_resolver(urlconf)
        else:
            resolver = get_resolver()
        
        resolver_match = resolver.resolve(request.path_info)
        callback, callback_args, callback_kwargs = resolver_match
        request.resolver_match = resolver_match
# 前面的分析可以查看之前的文章
# Apply view middleware
# 调用中间件的process_view,默认只有CsrfViewMiddleware.process_view
for middleware_method in self._view_middleware: response = middleware_method(request, callback, callback_args, callback_kwargs) if response: break # 上面process_view处理完request后正常返回是None,当有检查到request有异常时才返回response内容,因此正常请求会走if分支 if response is None:
# 包装视图函数,如果有将视图原子化的需要,会做一些处理,暂不深入分析 wrapped_callback
= self.make_view_atomic(callback) try:
# 调用视图函数,返回response response
= wrapped_callback(request, *callback_args, **callback_kwargs) except Exception as e: response = self.process_exception_by_middleware(e, request) # Complain if the view returned None (a common error). if response is None: if isinstance(callback, types.FunctionType): # FBV view_name = callback.__name__ else: # CBV view_name = callback.__class__.__name__ + '.__call__' raise ValueError( "The view %s.%s didn't return an HttpResponse object. It " "returned None instead." % (callback.__module__, view_name) ) # If the response supports deferred rendering, apply template # response middleware and then render the response
# 如果response支持延迟渲染,会调用中间件的process_template_response,最后调用response的render方法渲染响应后返回
elif hasattr(response, 'render') and callable(response.render): for middleware_method in self._template_response_middleware: response = middleware_method(request, response) # Complain if the template response middleware returned None (a common error). if response is None: raise ValueError( "%s.process_template_response didn't return an " "HttpResponse object. It returned None instead." % (middleware_method.__self__.__class__.__name__) ) try: response = response.render() except Exception as e: response = self.process_exception_by_middleware(e, request) return response

整个视图处理流程到这基本就结束了

下面分析一下django CBV相关代码,要实现CBV,我们再视图中定义的类需要继承django.views.View

我们在路由中调用了View.as_view(),这个方法返回了一个函数,是一个可调用对象,符合django路由的设置规则

class View:
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    def __init__(self, **kwargs):
        """
        Constructor. Called in the URLconf; can contain helpful extra
        keyword arguments, and other things.
        """
        # Go through keyword arguments, and either save their values to our
        # instance, or raise an error.
        for key, value in kwargs.items():
            setattr(self, key, value)

    @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))
# 视图函数,当wsgi调用视图函数时调用的就是这个函数
def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.setup(request, *args, **kwargs) if not hasattr(self, 'request'): raise AttributeError( "%s instance has no 'request' attribute. Did you override " "setup() and forget to call super()?" % cls.__name__ )
# 调用dispath方法,根据请求方法调用我们类中对应的方法,get,post等
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

def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list.
# 根据请求方法名获取到类中定义的方法,调用方法返回结果 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 return handler(request, *args, **kwargs)

视图相关代码先暂时分析到这里,后面有补充了再更新

下一篇分析下模型相关的代码

posted @ 2021-02-08 16:54  小麦香茶  阅读(133)  评论(0)    收藏  举报