使用python -m运行时Django无法找到burrow.settings的问题
python -m burrow报错但python burrow正常运行 问题描述
我正在开发一个名为meercat的项目,包含burrow(服务端)和lookout(客户端)两个子包。服务端burrow内有Django生成的样板代码(burrow/burrow子包)和Django REST Framework应用api。目前遇到以下问题:
- 执行
$ python burrow时程序正常运行 - 执行
$ python -m burrow时,抛出ModuleNotFoundError: No module named 'burrow.settings'错误
代码未使用相对导入,也未修改Django样板代码,尝试多种方法仍未定位原因。
项目结构
meercat - data - docs - meercat - burrow - api // 新建DRF应用 - burrow // Django startapp生成,未修改 - __init__.py - __main__.py - controller.py - manage.py - env - lookout - __init__.py - core.py README.md
核心代码(main.py)
# __main__.py import argparse as ap import logging import os import sys import django from django.core.exceptions import AppRegistryNotReady from django.core.management.color import supports_color try: os.environ.setdefault("DJANGO_SETTINGS_MODULE", "burrow.settings") django.setup() import controller except (AppRegistryNotReady, ModuleNotFoundError) as e: raise RuntimeError(f"Caught {e}: Ensure execution from correct location!") # 日志与argparse配置代码省略 def main() -> None: """Create and run a Meercat Burrow.""" vals: dict[str, Any] = vars(args) # argparse解析结果 return controller.main(vals) if __name__ == "__main__": sys.exit(main())
运行时sys.path对比
- 执行
/meercat/meercat$ python3 burrow时的sys.path:
[ '/home/memory_module/Code/meercat/meercat/burrow', '/usr/lib/python311.zip', '/usr/lib/python3.11', '/usr/lib/python3.11/lib-dynload', '/home/user/.local/lib/python3.11/site-packages', '/usr/local/lib/python3.11/dist-packages', '/usr/lib/python3/dist-packages' ]
- 执行
/meercat/meercat$ python3 -m burrow时的sys.path:
[ '/home/memory_module/Code/meercat/meercat', '/usr/lib/python311.zip', '/usr/lib/python3.11', '/usr/lib/python3.11/lib-dynload', '/home/user/.local/lib/python3.11/site-packages', '/usr/local/lib/python3.11/dist-packages', '/usr/lib/python3/dist-packages' ]
手动添加/home/memory_module/Code/meercat/meercat/burrow到路径未解决问题,但直接运行controller.main()(无论meercat/meercat/burrow$ python3 controller.py还是meercat/meercat/burrow$ python3 -m controller)均正常。
核心疑问
为什么__main__.py导入burrow.settings的表现和controller.py不同?问题出在哪里?
完整报错栈
Traceback (most recent call last): File "/home/memory_module/Code/meercat/meercat/burrow/__main__.py", line 20, in <module> django.setup() File "/home/rjn/.local/lib/python3.11/site-packages/django/__init__.py", line 19, in setup configure_logging(settings.LOGGING_CONFIG, settings.LOGGING) ^^^^^^^^^^^^^^^^^^^^^^^ File "/home/rjn/.local/lib/python3.11/site-packages/django/conf/__init__.py", line 92, in __getattr__ self._setup(name) File "/home/rjn/.local/lib/python3.11/site-packages/django/conf/__init__.py", line 79, in _setup self._wrapped = Settings(settings_module) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/rjn/.local/lib/python3.11/site-packages/django/conf/__init__.py", line 190, in __init__ mod = importlib.import_module(self.SETTINGS_MODULE) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "<frozen importlib._bootstrap>", line 1206, in _gcd_import File "<frozen importlib._bootstrap>", line 1178, in _find_and_load File "<frozen importlib._bootstrap>", line 1142, in _find_and_load_unlocked ModuleNotFoundError: No module named 'burrow.settings'
问题根源在于两种运行方式下的模块搜索上下文不同,导致Django对settings模块的路径解析出现偏差:
1. 路径解析差异的本质
python burrow:直接运行目录时,Python自动将burrow目录加入sys.path首位,此时burrow.settings指的是burrow/burrow/settings.py(因为burrow目录在搜索路径中,内部的burrow子包可直接被导入)。python -m burrow:以模块方式运行时,sys.path首位是meercat/meercat目录,此时burrow是顶层包,burrow.settings会被解析为burrow/settings.py(不存在的文件),而非实际存在的burrow/burrow/settings.py。
2. 可行修复方案
方案一:修正DJANGO_SETTINGS_MODULE的路径
将__main__.py中的设置改为完整的模块路径:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "burrow.burrow.settings")
无论哪种运行方式,Django都能准确定位到meercat/meercat/burrow/burrow/settings.py:
python -m burrow时,顶层包是burrow,burrow.burrow.settings对应子包内的settings模块python burrow时,sys.path包含burrow目录,burrow.burrow.settings同样能正确解析
方案二:统一sys.path搜索路径
在__main__.py的最开头(django.setup()之前),手动将burrow目录加入sys.path首位:
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
这样两种运行方式的sys.path首位都会是burrow目录,保证burrow.settings的解析逻辑一致。
注意:之前手动添加路径无效,大概率是添加时机太晚——必须在
django.setup()之前修改sys.path,否则Django已开始解析settings模块,路径修改无法生效。
3. 为什么controller.py运行正常?
直接运行controller.py或python -m controller时,sys.path的首位都是burrow目录,此时burrow.settings的解析逻辑和python burrow时一致,自然能找到正确的模块。
内容的提问来源于stack exchange,提问作者Blinkenlights

