Django框架如何处理项目内跨应用的模块导入?
Django跨App导入机制原理
首先明确一点:Django没有重写Python原生的导入逻辑,你写的跨App导入语句完全遵循Python标准导入规则,Django只在启动阶段做了最基础的路径初始化工作。
为什么平级App可以直接互相导入
你执行任何python manage.py xxx命令时,入口文件manage.py启动的第一时间就会做路径注入:把自身所在的目录(也就是你列的目录结构里,放another_app、some_app、some_project三个文件夹的项目根目录)添加到Python的模块搜索路径列表sys.path的最前端。
默认生成的manage.py里核心的路径处理逻辑等价于:
import sys import os BASE_DIR = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, BASE_DIR)
这一步做完,Python解释器找模块的时候,会优先从项目根目录开始检索。你在some_app/views.py里写from another_app.models import UserModel时,解释器的查找流程是:
- 遍历
sys.path里的所有路径,第一个命中的有效检索路径就是项目根目录 - 根目录下存在名为
another_app的文件夹,且自带__init__.py,是合法的Python包 - 继续在包内找到
models.py模块,加载其中的UserModel类完成导入
整个流程和普通Python项目的跨目录导入没有任何区别。
这里要澄清一个常见误区:
App能被导入和你在
settings.py的INSTALLED_APPS里注册它没有关系。INSTALLED_APPS的作用只是告诉Django哪些App需要加载模型、注册Admin后台、生成迁移文件、接入信号逻辑。就算你不把某个App加到INSTALLED_APPS里,只要它所在的目录在sys.path搜索范围内,你依然可以正常导入里面的普通函数、类,只是和Django框架强相关的模型等功能不会生效而已。
独立目录模块互相调用的配置方案
如果你的项目里有和App平级的独立目录需要跨模块调用,照着下面的规则配置就不会出导入问题:
- 如果独立目录直接放在项目根目录下:不需要额外改任何配置,只要目录本身是合法Python包(带
__init__.py,Python3.3+支持隐式命名空间包可以不加,但为了兼容性建议加上),直接用from 目录名.模块名 import 目标对象的绝对导入写法即可,和平级App导入逻辑完全一致。 - 如果独立目录放在其他层级:只需要把该目录的父目录路径加到
sys.path里即可,和manage.py注入根目录的逻辑一样。 - 尽量不要用跨顶层包的相对导入(比如在some_app里写
from ..another_app.models import UserModel),这种写法对执行入口的路径要求很苛刻,很容易触发ImportError: attempted relative import with no known parent package报错,从根路径写绝对导入是Django官方推荐的最稳定写法。
内容的提问来源于stack exchange,提问作者pooooky
相关产品推荐
相关产品推荐

