django的路由源碼過程剖析

在以前的文章中已經提到每當客戶端的請求過來的時候都會將請求交給WSGIHandler類,在WSGIHandler對象的call方法中會調用到WSGIHandler的父類django.core.handlers.base.BaseHandler的get_response方法django

 1 class WSGIHandler(base.BaseHandler):
 2     request_class = WSGIRequest
 3 
 4     def __init__(self, *args, **kwargs):
 5         super().__init__(*args, **kwargs)
 6         self.load_middleware()  #加載middleware
 7 
 8     def __call__(self, environ, start_response):
 9         set_script_prefix(get_script_name(environ))
10         signals.request_started.send(sender=self.__class__, environ=environ)
11         request = self.request_class(environ)  #實例化request類
12         response = self.get_response(request)  #調用父類的方法
13 
14         response._handler_class = self.__class__
15 
16         status = '%d %s' % (response.status_code, response.reason_phrase)
17         response_headers = list(response.items())
18         for c in response.cookies.values():
19             response_headers.append(('Set-Cookie', c.output(header='')))
20         start_response(status, response_headers)
21         if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
22             response = environ['wsgi.file_wrapper'](response.file_to_stream)
23         return response

首先在初始化中調用load_middleware方法cookie

    def load_middleware(self):
        """
        Populate middleware lists from settings.MIDDLEWARE.

        Must be called after the environment is fixed (see __call__ in subclasses).
        """
        self._view_middleware = []
        self._template_response_middleware = []
        self._exception_middleware = []

        handler = convert_exception_to_response(self._get_response)
        for middleware_path in reversed(settings.MIDDLEWARE):  #反轉並循環settings中定義的中間件
            middleware = import_string(middleware_path)
            try:
                mw_instance = middleware(handler)
            except MiddlewareNotUsed as exc:
                if settings.DEBUG:
                    if str(exc):
                        logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
                    else:
                        logger.debug('MiddlewareNotUsed: %r', middleware_path)
                continue

            if mw_instance is None:
                raise ImproperlyConfigured(
                    'Middleware factory %s returned None.' % middleware_path
                )

            if hasattr(mw_instance, 'process_view'): #若是該實例對象包含process_view方法,則將其插入到_view_middleware列表的第一個位置
                self._view_middleware.insert(0, mw_instance.process_view)
            if hasattr(mw_instance, 'process_template_response'): 如下同上
                self._template_response_middleware.append(mw_instance.process_template_response)
            if hasattr(mw_instance, 'process_exception'): 
                self._exception_middleware.append(mw_instance.process_exception)

            handler = convert_exception_to_response(mw_instance)  #最後把該實例對象當作參數傳入作判斷

        # We only assign to this when initialization is complete as it is used
        # as a flag for initialization being complete.
        self._middleware_chain = handler  #獲取響應
def convert_exception_to_response(get_response):
    """
    Wrap the given get_response callable in exception-to-response conversion.
  
    All exceptions will be converted. All known 4xx exceptions (Http404,
    PermissionDenied, MultiPartParserError, SuspiciousOperation) will be
    converted to the appropriate response, and all other exceptions will be
    converted to 500 responses.
  
    This decorator is automatically applied to all middleware to ensure that
    no middleware leaks an exception and that the next middleware in the stack
    can rely on getting a response instead of an exception.
    """
    @wraps(get_response)
    def inner(request):
        try:
            response = get_response(request)
        except Exception as exc:
            response = response_for_exception(request, exc)  #對於中間件拋出的異常進行攔截,判斷響應的是什麼錯誤,已知的拋出4xx,未知的都是500
        return response
    return inner

在get_response方法中app

    def get_response(self, request):
        """Return an HttpResponse object for the given HttpRequest."""
        # Setup default url resolver for this thread
        set_urlconf(settings.ROOT_URLCONF)  #加載settings中的urlconf

        response = self._middleware_chain(request)  #獲取response

        response._closable_objects.append(request)

        # If the exception handler returns a TemplateResponse that has not
        # been rendered, force it to be rendered.
        if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)):
            response = response.render()

        if response.status_code >= 400:
            log_response(
                '%s: %s', response.reason_phrase, request.path,
                response=response,
                request=request,
            )

        return response

找_get_response方法中ide

    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  #callback是views.py中定義的view函數
        request.resolver_match = resolver_match

        # Apply view middleware
        for middleware_method in self._view_middleware:
            response = middleware_method(request, callback, callback_args, callback_kwargs)
            if response:
                break

        if response is None:
            wrapped_callback = self.make_view_atomic(callback)
            try:
                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
        elif hasattr(response, 'render') and callable(response.render):  #若是返回的響應對象有render
            for middleware_method in self._template_response_middleware:  #加載到template中
                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

在路由解析函數resolve中函數

    def resolve(self, path):
        path = str(path)  # path may be a reverse_lazy object
        tried = []
        match = self.pattern.match(path)  #正則匹配路由,匹配成功則進行下一步解析
        if match:
            new_path, args, kwargs = match
            for pattern in self.url_patterns:
                try:
                    sub_match = pattern.resolve(new_path) #循環匹配
                except Resolver404 as e:  #失敗就拋出404錯誤
                    sub_tried = e.args[0].get('tried')
                    if sub_tried is not None:
                        tried.extend([pattern] + t for t in sub_tried)
                    else:
                        tried.append([pattern])
                else:
                    if sub_match:
                        # Merge captured arguments in match with submatch
                        sub_match_dict = {**kwargs, **self.default_kwargs}
                        # Update the sub_match_dict with the kwargs from the sub_match.
                        sub_match_dict.update(sub_match.kwargs)
                        # If there are *any* named groups, ignore all non-named groups.
                        # Otherwise, pass all non-named arguments as positional arguments.
                        sub_match_args = sub_match.args
                        if not sub_match_dict:
                            sub_match_args = args + sub_match.args
                        return ResolverMatch(
                            sub_match.func,  #這個是views.py中定義的視圖函數
                            sub_match_args,
                            sub_match_dict,
                            sub_match.url_name,
                            [self.app_name] + sub_match.app_names,
                            [self.namespace] + sub_match.namespaces,
                        )
                    tried.append([pattern])
            raise Resolver404({'tried': tried, 'path': new_path})
        raise Resolver404({'path': path})
相關文章
相關標籤/搜索