版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
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’>],即一个类对象的列表。