Python importlib.import_module方法以及在Django中的使用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/JosephThatwho/article/details/102533939

importlib模块为用户提供了动态导入自定义对象的途径。比如自定义三个权限验证模块

" Press ? for help             |  1 class Authentication:
                               |  2     def __init__(self):
.. (up a dir)                  |  3     ¦   print ('Has First Authentication')
</Desktop/learn/django/auth/   |~                                                                               
  __init__.py                  |~                                                                               
  firauthentication.py         |~                                                                               
  secauthentication.py         |~                                                                               
  thiauthentication.py         | firauthentication.py                               pyt…   33%1/3:  1 
~                              |  1 class Authentication:
~                              |  2     def __init__(self):
~                              |  3     ¦   print ('Has Second Authentication')
~                              |~                                                                               
~                              |~                                                                               
~                              |~                                                                               
~                              |~                                                                               
~                              | secauthentication.py                               pyt…   33%1/3:  9 
~                              |  1 class Authentication:
~                              |  2     def __init__(self):
~                              |  3     ¦   print ('Has Second Authentication')
~                              |~                                                                               
~                              |~                                                                               
~                              |~                                                                               
~                              |~                                                                               
<arx/Desktop/learn/django/auth   thiauthentication.py                               pyt…   33%1/3:  1 

现在可以根据配置文件导入应用中:

>>> import importlib
>>> AUTHENTICATION_LIST = ['auth.firauthentication', 'auth.secauthentication']
>>> for AUTH in AUTHENTICATION_LIST:
...     authModule = importlib.import_module(AUTH)  # 获取模块
...     print(authModule)  # 检查模块对象
...     print(type(authModule))  # 检查获取的对象的类型
...     auth = getattr(authModule, 'Authentication')  # 获取定在模块内的'Authentication'类对象
...     realAuth = auth()  # 实例化类对象
... 
<module 'auth.firauthentication' from '/home/starx/Desktop/learn/django/auth/firauthentication.py'>
<class 'module'>
Has First Authentication
<module 'auth.secauthentication' from '/home/starx/Desktop/learn/django/auth/secauthentication.py'>
<class 'module'>
Has Second Authentication

可以看到import_module方法接受以点分隔的模块路径,并返回该模块,此时可以调用模块中的内容。
Django中多次使用importlib模块,以权限验证为例,django.auth模块中定义了_get_backends方法,此方法会返回所有配置在settings中的认证后端对象,代码如下:

def _get_backends(return_tuples=False):
    backends = []
    for backend_path in settings.AUTHENTICATION_BACKENDS:
        backend = load_backend(backend_path)
        backends.append((backend, backend_path) if return_tuples else backend)
    if not backends:
        raise ImproperlyConfigured(
            'No authentication backends have been defined. Does '
            'AUTHENTICATION_BACKENDS contain anything?'
        )
    return backends

可以看到,对于定义在settings下的AUTHENTICATION_BACKENDS中的认证后端的路径(Django默认的AUTHENTICATION_BACKENDS内仅有一条'django.contrib.auth.backends.ModelBackend'),会依次调用load_backend方法,代码如下:

def load_backend(path):
    return import_string(path)

import_string方法定义在utils.module_loading.py中:

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, class_name = dotted_path.rsplit('.', 1)
    except ValueError as err:
        raise ImportError("%s doesn't look like a module path" % dotted_path) from err
    ## 对于的django自定义的AUTHENTICATION_BACKENDS:
    ## 'django.contrib.auth.backends.ModelBackend'
    ## module_path = 'django.contrib.auth.backends'
    ## class_name = 'ModelBackend'

    module = import_module(module_path)  # 此时module就是backends模块

    try:
        return getattr(module, class_name)  # 返回定义在backends中的‘ModelBackend’类
    except AttributeError as err:
        raise ImportError('Module "%s" does not define a "%s" attribute/class' % (
            module_path, class_name)
        ) from err

所以默认情况下_get_backends最终返回的是[<class ‘django.contrib.auth.backends.ModelBackend’>],即一个类对象的列表。

猜你喜欢

转载自blog.csdn.net/JosephThatwho/article/details/102533939
今日推荐