• Django中模块的加载原理


    Django中的module的加载是通过反射来完成的,借助importlib中的import_module函数来实现的动态加载。import_module的内部通过使用了递归和线程锁,字符串的切割,实现模块的加载。

    主要有以下几个步骤:

    根据字符串的形式导入模块

    假设在有以下的类跟方法:

    path = "handler.basic.BaseHandler"

    func_name = "process_request"

    导入目标函数:

    import importlib
    
    # 通过切割拿到模块和类名
    module_path,cls_name = path.rsplit('.', 1)
    # 导入模块
    module = importlib.import_module(module_path)
    print(module)
    

    去模块中找到相应的类

    通过反射拿到类。

    cls =  getattr(module, cls)
    

    根据相应的类实例化

    实例化对象:

    obj = cls()
    

    执行对象方法

    通过反射拿到方法,

    func = getattr(obj, func_name)
    fuc()
    

    Django中间件源码

        def load_middleware(self):
            """
            Populate middleware lists from settings.MIDDLEWARE (or the deprecated
            MIDDLEWARE_CLASSES).
    
            Must be called after the environment is fixed (see __call__ in subclasses).
            """
            self._request_middleware = []
            self._view_middleware = []
            self._template_response_middleware = []
            self._response_middleware = []
            self._exception_middleware = []
    
            if settings.MIDDLEWARE is None:
                warnings.warn(
                    "Old-style middleware using settings.MIDDLEWARE_CLASSES is "
                    "deprecated. Update your middleware and use settings.MIDDLEWARE "
                    "instead.", RemovedInDjango20Warning
                )
                handler = convert_exception_to_response(self._legacy_get_response)
                for middleware_path in settings.MIDDLEWARE_CLASSES:
                    mw_class = import_string(middleware_path)
                    try:
                        mw_instance = mw_class()
                    except MiddlewareNotUsed as exc:
                        if settings.DEBUG:
                            if six.text_type(exc):
                                logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
                            else:
                                logger.debug('MiddlewareNotUsed: %r', middleware_path)
                        continue
    
                    if hasattr(mw_instance, 'process_request'):
                        self._request_middleware.append(mw_instance.process_request)
                    if hasattr(mw_instance, 'process_view'):
                        self._view_middleware.append(mw_instance.process_view)
                    if hasattr(mw_instance, 'process_template_response'):
                        self._template_response_middleware.insert(0, mw_instance.process_template_response)
                    if hasattr(mw_instance, 'process_response'):
                        self._response_middleware.insert(0, mw_instance.process_response)
                    if hasattr(mw_instance, 'process_exception'):
                        self._exception_middleware.insert(0, mw_instance.process_exception)
            else:
                handler = convert_exception_to_response(self._get_response)
                for middleware_path in reversed(settings.MIDDLEWARE):
                    # 从setting中的中间件的配置,切割拿到导入的模块和类名,通过反射拿到对应的类
                    middleware = import_string(middleware_path)
                    try:
                        # 中间件实例化对象,
                        mw_instance = middleware(handler)
                    except MiddlewareNotUsed as exc:
                        if settings.DEBUG:
                            if six.text_type(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'):
                        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 import_string(dotted_path):
        """
        Import a dotted module path and return the attribute/class designated by the
        last name in the path. Raise ImportError if the import failed.
        """
        try:
            # module_path: django.middleware.csrf
            # class_name: CsrfViewMiddleware
            module_path, class_name = dotted_path.rsplit('.', 1)
        except ValueError:
            msg = "%s doesn't look like a module path" % dotted_path
            six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
    
        # module_path: django.middleware.csrf
        # 通过module_path导入模块
        module = import_module(module_path)
    
        try:
            # 拿到当前类的类名
            return getattr(module, class_name)
        except AttributeError:
            msg = 'Module "%s" does not define a "%s" attribute/class' % (
                module_path, class_name)
            six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
    
    #####################################################################
    
    def import_module(name, package=None):
        """Import a module.
    
        The 'package' argument is required when performing a relative import. It
        specifies the package to use as the anchor point from which to resolve the
        relative import to an absolute import.
    
        """
        level = 0
        if name.startswith('.'):
            if not package:
                msg = ("the 'package' argument is required to perform a relative "
                       "import for {!r}")
                raise TypeError(msg.format(name))
            for character in name:
                if character != '.':
                    break
                level += 1
        # _gcd_import中使用了递归和线程锁,字符串的切割,实现模块的加载。
        return _bootstrap._gcd_import(name[level:], package, level)
    
  • 相关阅读:
    webpack学习遇到大坑(纯属自己记录)
    git忽略某些文件提交
    数据结构(一)创建并遍历线性列表
    数据结构二 顺序表的创建
    JqGrid动态改变列名
    构造DataTable
    计算机存储数据的单位
    .NET Core在WindowsServer服务器部署(使用Web Deploy发布)
    mysql ERROR 1045 (28000): 错误解决办法
    ASP.NET取得Request URL的各个部分
  • 原文地址:https://www.cnblogs.com/linga/p/10493551.html
Copyright © 2020-2023  润新知