求助解决Django中相对导入报错:ImportError: attempted relative import beyond top-level package
我之前碰到过完全一样的问题,咱们先把问题捋明白:你在online_book/shop-cart/cart.py里用from ..books.models import Book触发了ImportError,核心原因是Python对相对导入的解析规则和Django项目的运行路径不匹配。
先确认你的目录结构应该是这样的(补全了Python识别包必需的文件):
online_book/ # 这是你的项目根目录,也是Python该识别的顶级包 ├── books/ │ ├── __init__.py │ └── models.py └── shop-cart/ ├── __init__.py └── cart.py
下面是几个靠谱的解决方案,按推荐程度排序:
1. 改用绝对导入(Django项目首选)
在Django项目里,官方更推荐用绝对导入,因为Django会自动把项目根目录加入Python的sys.path。你只需要把导入代码改成:
from books.models import Book
如果你的项目有重名app,或者需要更明确的路径,也可以写全顶级包路径:
from online_book.books.models import Book
这种方式完全避开了相对导入的路径坑,也是Django开发者最常用的写法。
2. 从项目根目录的父级运行代码(保留相对导入的情况)
如果你坚持要用相对导入,绝对不能直接双击或者用python shop-cart/cart.py运行这个文件——这会让Python把shop-cart当成顶级包,..就会超出这个范围导致报错。
正确的做法是从online_book的父目录(也就是包含online_book的那个文件夹)运行命令,用Python的模块运行方式:
python -m online_book.shop-cart.cart
不过这里有个小提醒:Python的包名不建议用连字符(-),容易和减号混淆,最好把shop-cart改成shop_cart,这样命令更顺畅:
python -m online_book.shop_cart.cart
3. 检查包的初始化文件
确保books和shop-cart目录下都有__init__.py文件(可以是空文件),这是Python识别目录为合法包的必要条件。如果缺少这个文件,相对导入也会出现各种奇怪的错误。
为什么会出现这个错误?
简单来说:当你直接运行cart.py时,Python会把cart.py所在的shop-cart目录当作顶级包,这时候..试图访问shop-cart的父目录(online_book),而这个父目录不在当前的顶级包范围内,所以Python就会抛出"超出顶级包"的错误。而Django的runserver命令是从项目根目录启动的,这时候online_book才是顶级包,但绝对导入依然是更稳妥的选择。
内容的提问来源于stack exchange,提问作者Dimaapp

