当你的模块文件越来越多,就需要对模块文件进行划分,比如把负责跟数据库交互的都放一个文件夹,把与页面交互相互的放入一个文件夹。

        像上面这样,一个文件夹管理多个模块文件,这个文件夹就被称为包。

        那不同包之间的模块如何相互导入呢?

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 需要满足两个条件:

  1. 文件夹中必须有 __init__.py 文件,该文件可以为空,但必须存在该文件。
  2. 不能作为顶层模块来执行该文件夹中的 py 文件(即不能作为主函数的入口)。

        所以这个问题的解决办法就是,既然你在 views.py 里执行了相对导入,那就不要把 view.py 当作入口程序,可以通过上一级的 manage.py 调用 views.py 。

        正确的代码目录结构如下:

再执行 manage.py 就不会报错了。

注:虽然 python 支持相对导入,但对模块间的路径关系要求比较严格,处理不当就容易出错,so并不建议在项目里经常使用。