Django项目启动报错ImportError:无法导入get_rule_detail
解决Django项目循环导入导致的ImportError问题
问题现象
启动Django项目时抛出ImportError,报错信息如下:
2022-09-01 09:22:51,525 [MainThread:25612] [django.utils.autoreload:612] [INFO]- Watching for file changes with StatReloader Exception in thread django-main-thread: Traceback (most recent call last): File "C:\Python37\lib\threading.py", line 926, in _bootstrap_inner self.run() File "C:\Python37\lib\threading.py", line 870, in run self._target(*self._args, **self._kwargs) File "C:\Python37\lib\site-packages\django\utils\autoreload.py", line 53, in wrapper fn(*args, **kwargs) File "C:\Python37\lib\site-packages\django\core\management\commands\runserver.py", line 118, in inner_run self.check(display_num_errors=True) File "C:\Python37\lib\site-packages\django\core\management\base.py", line 396, in check databases=databases, File "C:\Python37\lib\site-packages\django\core\checks\registry.py", line 70, in run_checks new_errors = check(app_configs=app_configs, databases=databases) File "C:\Python37\lib\site-packages\django\core\checks\urls.py", line 13, in check_url_config return check_resolver(resolver) File "C:\Python37\lib\site-packages\django\core\checks\urls.py", line 23, in check_resolver return check_method() File "C:\Python37\lib\site-packages\django\urls\resolvers.py", line 408, in check for pattern in self.url_patterns: File "C:\Python37\lib\site-packages\django\utils\functional.py", line 48, in __get__ res = instance.__dict__[self.name] = self.func(instance) File "C:\Python37\lib\site-packages\django\urls\resolvers.py", line 589, in url_patterns patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module) File "C:\Python37\lib\site-packages\django\utils\functional.py", line 48, in __get__ res = instance.__dict__[self.name] = self.func(instance) File "C:\Python37\lib\site-packages\django\urls\resolvers.py", line 582, in urlconf_module return import_module(self.urlconf_name) File "C:\Python37\lib\importlib\__init__.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1006, in _gcd_import File "<frozen importlib._bootstrap>", line 983, in _find_and_load File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 677, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 728, in exec_module File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed File "D:\code\ido-jira-plug\IdoJiraPlug\IdoJiraPlug\urls.py", line 23, in <module> path('jira/', include('jira_plug.urls', namespace='jira_plug')), File "C:\Python37\lib\site-packages\django\urls\conf.py", line 34, in include urlconf_module = import_module(urlconf_module) File "C:\Python37\lib\importlib\__init__.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1006, in _gcd_import File "<frozen importlib._bootstrap>", line 983, in _find_and_load File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 677, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 728, in exec_module File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed File "D:\code\ido-jira-plug\IdoJiraPlug\jira_plug\urls.py", line 5, in <module> from . import api File "D:\code\ido-jira-plug\IdoJiraPlug\jira_plug\api\__init__.py", line 3, in <module> from .config import * File "D:\code\ido-jira-plug\IdoJiraPlug\jira_plug\api\config.py", line 5, in <module> from jira_plug.utils import JiraAction File "D:\code\ido-jira-plug\IdoJiraPlug\jira_plug\utils\__init__.py", line 6, in <module> from .rule import * File "D:\code\ido-jira-plug\IdoJiraPlug\jira_plug\utils\rule.py", line 4, in <module> from jira_plug.serializers import RuleConfigInfoSerializer File "D:\code\ido-jira-plug\IdoJiraPlug\jira_plug\serializers\__init__.py", line 4, in <module> from .request_serializer import * File "D:\code\ido-jira-plug\IdoJiraPlug\jira_plug\serializers\request_serializer.py", line 6, in <module> from jira_plug.utils import JiraAction, get_msg_data, get_rule_detail, handle_message_content ImportError: cannot import name 'get_rule_detail' from 'jira_plug.utils' (D:\code\ido-jira-plug\IdoJiraPlug\jira_plug\utils\__init__.py)
项目结构
IdoJiraPlug - jira_plug - __init__.py - api __init__.py config.py - serializers __init__.py request_serializer.py - utils __init__.py rule.py - urls.py - manage.py
相关文件代码
jira_plug/utils/init.py
from .rule import *
jira_plug/utils/rule.py
... from jira_plug.serializers import RuleConfigInfoSerializer ...
jira_plug/serializers/init.py
from .request_serializer import *
jira_plug/serializers/request_serializer.py
... from jira_plug.utils import JiraAction, get_msg_data, get_rule_detail, handle_message_content ...
问题分析
确实是循环导入导致的问题,完整导入链如下:
- 项目启动加载urls时,触发
api/config.py导入jira_plug.utils utils/__init__.py导入rule.pyrule.py导入jira_plug.serializers,而serializers/__init__.py导入request_serializer.pyrequest_serializer.py尝试从jira_plug.utils导入get_rule_detail,但此时rule.py还未完成加载,get_rule_detail还没被注册到utils模块中,因此抛出ImportError。
解决方案
方法1:延迟导入(快速修复)
把需要导入的函数放到使用它的函数内部,而非模块顶部,避开导入时的循环依赖:
# 修改jira_plug/serializers/request_serializer.py # 移除顶部的get_rule_detail导入,保留其他 from jira_plug.utils import JiraAction, get_msg_data, handle_message_content # 在用到get_rule_detail的函数内导入 def your_function(): from jira_plug.utils.rule import get_rule_detail # 这里正常使用get_rule_detail
方法2:直接导入具体模块,跳过__init__中转
调整导入路径,直接从具体文件导入,避免通过包的__init__模块中转,打破循环链:
# 修改jira_plug/serializers/request_serializer.py的导入语句 from jira_plug.utils import JiraAction, get_msg_data, handle_message_content from jira_plug.utils.rule import get_rule_detail # 直接从rule.py导入
同时调整rule.py的导入,直接指向序列化器文件:
# 修改jira_plug/utils/rule.py的导入语句 from jira_plug.serializers.request_serializer import RuleConfigInfoSerializer # 直接导入具体序列化器
方法3:重构代码拆分依赖(长期方案)
如果get_rule_detail这类工具函数和序列化器的依赖可以分离,把不依赖序列化器的公共工具函数拆分到独立模块(比如utils/common.py),让两边都从这个新模块导入,彻底消除循环依赖。
内容的提问来源于stack exchange,提问作者陈俊汝
相关产品推荐
相关产品推荐

