删除Django应用后出现ImportError(循环导入)问题求助
Django删除应用后触发循环导入错误的解决思路
问题描述
要删除Django项目中的app_one应用,但清空app_one/models.py的内容后,其他应用出现ImportError。奇怪的是,只要在app_one/models.py中保留一行代码from app_three.tasks import some_task,程序就能正常运行。三个应用间无实际业务关联,尝试过将相关导入移至app_two/apps.py的AppsConfig.ready方法、调整应用初始化顺序,均未解决问题。
相关代码结构
app_one/models.py(待删除)app_two/models.py、app_two/service.pyapp_three/tasks.py
相关代码片段
app_two - mapping_service.py
from double_gis.models import DoubleGisCompanyState
app_two - double_gis/models.py
from company.models import Brand, BrandFeature, Company, Owner, get_pydantic_for_features class DoubleGisCompanyState(models.Model): class Meta: verbose_name = _('2GIS Company state') verbose_name_plural = _('2GIS Companies states') company = models.OneToOneField(Company, verbose_name=_('company'), on_delete=models.CASCADE) state = models.CharField(verbose_name=_('state'), max_length=32, choices=states, db_index=True) state_changed_at = models.DateTimeField(null=True, editable=False, verbose_name=_('State changed at'),) double_gis_id = models.CharField( verbose_name=_('2GIS ID'), max_length=128, default=None, null=True, blank=True, unique=True, )
报错信息
Traceback (most recent call last): File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/./manage.py", line 22, in <module> execute_from_command_line(sys.argv) File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/.env/lib/python3.10/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line utility.execute() File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/.env/lib/python3.10/site-packages/django/core/management/__init__.py", line 420, in execute django.setup() File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/.env/lib/python3.10/site-packages/django/__init__.py", line 24, in setup apps.populate(settings.INSTALLED_APPS) File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/.env/lib/python3.10/site-packages/django/apps/registry.py", line 116, in populate app_config.import_models() File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/.env/lib/python3.10/site-packages/django/apps/config.py", line 304, in import_models self.models_module = import_module(models_module_name) File "/Users/vaceslavksendzov/.pyenv/versions/3.10.5/lib/python3.10/importlib/__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1050, in _gcd_import File "<frozen importlib._bootstrap>", line 1027, in _find_and_load File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 688, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 883, in exec_module File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/double_gis/models.py", line 34, in <module> from double_gis.client import AddressDetails, BranchDetails, OrganizationCommonFields File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/double_gis/client.py", line 32, in <module> from company.modules.reviews.services.review_abuse_service.exceptions import ReviewDoesNotExists File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/company/modules/reviews/services/review_abuse_service/__init__.py", line 2, in <module> from .services import CatalogReviewAbuse, ReviewAbuseService File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/company/modules/reviews/services/review_abuse_service/services.py", line 17, in <module> from company.modules.reviews.tasks.reviews_microservice import send_abuse_to_reviews_microservice File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/company/modules/reviews/tasks/__init__.py", line 15, in <module> from company.modules.reviews.tasks.notifications import ( File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/company/modules/reviews/tasks/notifications.py", line 14, in <module> from company.modules.reviews.services import notifications File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/company/modules/reviews/services/notifications/__init__.py", line 2, in <module> from company.modules.reviews.services.notifications.builder_service import BuilderService File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/company/modules/reviews/services/notifications/builder_service.py", line 18, in <module> from double_gis_partnership.services import DoubleGisCompanyBrandMappingService File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/double_gis_partnership/services.py", line 31, in <module> from double_gis.mapping_service import ACLDoubleGisMappingService File "/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/double_gis/mapping_service.py", line 9, in <module> from double_gis.models import DoubleGisCompanyState ImportError: cannot import name 'DoubleGisCompanyState' from partially initialized module 'double_gis.models' (most likely due to a circular import) (/Users/vaceslavksendzov/Desktop/RD/rocketdata/backend/app/double_gis/models.py)
解决思路
理解临时补丁的本质:保留
from app_three.tasks import some_task时,该导入会提前触发app_three及相关模块的初始化,间接改变了Django加载应用的顺序,刚好避开了double_gis模块的循环导入问题。这行代码只是临时补丁,并未真正解决循环依赖。修复
double_gis模块的循环导入:从报错栈可见,double_gis/models.py导入了double_gis/client.py,而client.py最终又绕回导入依赖double_gis.models的模块,形成循环。- 将
double_gis/models.py第34行的模块级导入移至函数内部:# 移除模块顶部的导入 # from double_gis.client import AddressDetails, BranchDetails, OrganizationCommonFields # 在需要用到的函数内导入 def your_function(): from double_gis.client import AddressDetails, BranchDetails, OrganizationCommonFields # 业务逻辑代码 - 如果这些类用于模型字段或序列化,可改用字符串引用(如Django外键的
'app.Model'形式),或把公共类抽离到独立的utils模块,避免跨模块循环导入。
- 将
彻底移除
app_one的步骤:- 先解决上述循环导入问题,确保无
app_one时项目能正常运行。 - 从
settings.py的INSTALLED_APPS中移除app_one的配置项。 - 删除
app_one的所有文件,以及项目中其他对app_one的引用(如路由、admin配置等)。
- 先解决上述循环导入问题,确保无
调整应用加载顺序:若调整导入仍有问题,可在
INSTALLED_APPS中将double_gis相关应用移至company应用之前,让double_gis的模型先完成初始化,再加载依赖它的company模块。
内容的提问来源于stack exchange,提问作者Skenz_sl
相关产品推荐
相关产品推荐

