zoukankan      html  css  js  c++  java
  • django的路由源码过程剖析

    在之前的文章中已经提到每当客户端的请求过来的时候都会将请求交给WSGIHandler类,在WSGIHandler对象的call方法中会调用到WSGIHandler的父类django.core.handlers.base.BaseHandler的get_response方法

     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方法

        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方法中

        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方法中

        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})
  • 相关阅读:
    记第一场cf比赛(Codeforces915)
    Uva11468:Substring
    Uva11732:"strcmp()" Anyone?
    Uva1014:Remember the Word
    洛谷P2502:[HAOI2006]旅行
    bzoj3677: [Apio2014]连珠线
    bzoj4906: [BeiJing2017]喷式水战改
    海上孤独的帆
    Treap基本用法总结
    noip2017考前基础复习——数论数学
  • 原文地址:https://www.cnblogs.com/arrow-kejin/p/10364942.html
Copyright © 2011-2022 走看看