当你的模块文件越来越多,就需要对模块文件进行划分,比如把负责跟数据库交互的都放一个文件夹,把与页面交互相互的放入一个文件夹。
像上面这样,一个文件夹管理多个模块文件,这个文件夹就被称为包。
那不同包之间的模块如何相互导入呢?
crm/views.py 内容
def sayhi():
print('hello world!')
通过 manage.py 调用
from my_pro.crm import views #从包里导入包里的文件
views.sayhi()
在文件夹下,加一个 __inint__.py 这个文件就会被 python2 识别为一个包,python3 不加也能被识别为包。
从 manage.py 里导入 views.py,从 views.py 里导入 settings.py。因为在 sys.path 里已经把 manage.py 所在的位置当作入口导入,即 sys.path 里的 " " ,所以 views.py 可以从高它一级的 proj 里导入 settings.py 。
从 views.py 里直接导入 settings.py ,而 settings.py 存在于高 views.py 一级的 proj 里,由于入口文件是 views.py ,所以 settings.py 不存在于 sys.path 里面,需要获取settings 的绝对路径添加到 sys.path 里,进行模块导入。
import sys, os
#获取此程序所在文件的绝对目录的上一层的上一层,即proj所在绝对路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
#将proj所在文件路径添加到sys.path里面,即导入模块的搜寻范围
sys.path.append(BASE_DIR)
from proj import settings
相对导入
从当前目录下直接导入,意思是被导入的文件和导入文件二者为同级别文件,存在于同一个文件夹下。
#在 views.py 里导入 models.py
from . import models
在 views.py 里导入 settings.py
# '.' 代表当前目录,那 '..proj' 应该就能代表当前目录的平级中的 proj 文件
from ..proj import settings
执行结果报错了
SystemError: Parent module '' not loaded, cannot perform relative import
或者有人会看到这个错
ValueError: attempted relative import beyond top-level package
其实这两个错误的原因归根结底是一样的:在涉及到相对导入时,package 所对应的文件夹必须正确的被 python 解释器视作 package ,而不是普通文件夹。否则由于不被视作 package ,无法利用 package 之间的嵌套关系实现 python 中包的相对导入。
文件夹被视 python 解释器视作 package 需要满足两个条件:
- 文件夹中必须有 __init__.py 文件,该文件可以为空,但必须存在该文件。
- 不能作为顶层模块来执行该文件夹中的 py 文件(即不能作为主函数的入口)。
所以这个问题的解决办法就是,既然你在 views.py 里执行了相对导入,那就不要把 view.py 当作入口程序,可以通过上一级的 manage.py 调用 views.py 。
正确的代码目录结构如下:
再执行 manage.py 就不会报错了。
注:虽然 python 支持相对导入,但对模块间的路径关系要求比较严格,处理不当就容易出错,so并不建议在项目里经常使用。