Django多进程运行时循环导入与Apps未加载问题求助
Django多进程调用数据库:解决Apps aren't loaded yet与循环导入问题
问题场景
在Django项目中使用多进程执行数据库查询时,触发Apps aren't loaded yet.错误;尝试在数据库查询模块添加import django; django.setup()后,又出现循环导入错误。仅在多进程调用时出现问题,单进程模式下功能正常。
项目代码示例
models.py
from django.db import models class Document(models.Model): name = models.CharField(max_length=20) text = models.CharField(max_length=200)
db_request.py
from .models import Document def get_all_documents(): return Document.objects.all()
services.py
from multiprocessing import Process from .db_request import get_all_documents def stream(): docs = get_all_documents() def start_streams_documents(): pr = Process(target=stream) pr.start() pr.join()
admin.py
from .models import Document from .services import start_streams_documents @admin.register(Document) class MachineAdmin(admin.ModelAdmin): list_display = ('name','text') change_list_template = 'admin/document_table_changelist.html' def get_urls(self): urls = super().get_urls() my_urls = [path('start_streams/', self.start_streams)] return my_urls + urls def start_streams(self, request): start_streams_documents() return HttpResponseRedirect("../")
报错堆栈信息
Traceback (most recent call last): File "<string>", line 1, in <module> File "C:\Users\fr3st\AppData\Local\Programs\Python\Python311\Lib\multiprocessing\spawn.py", line 120, in spawn_main exitcode = _main(fd, parent_sentinel) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\fr3st\AppData\Local\Programs\Python\Python311\Lib\multiprocessing\spawn.py", line 130, in _main self = reduction.pickle.load(from_parent) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\fr3st\Desktop\Screener V3\app\documents\services.py", line 3, in <module> from .db_request import get_all_documents File "C:\Users\fr3st\Desktop\Screener V3\app\documents\db_request.py", line 2, in <module> django.setup() File "C:\Users\fr3st\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\__init__.py", line 24, in setup apps.populate(settings.INSTALLED_APPS) File "C:\Users\fr3st\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\apps\registry.py", line 125, in populate app_config.ready() File "C:\Users\fr3st\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\contrib\admin\apps.py", line 27, in ready self.module.autodiscover() File "C:\Users\fr3st\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\contrib\admin\__init__.py", line 50, in autodiscover autodiscover_modules("admin", register_to=site) File "C:\Users\fr3st\AppData\Local\Programs\Python\Python311\Lib\site-packages\django\utils\module_loading.py", line 58, in autodiscover_modules import_module("%s.%s" % (app_config.name, module_to_search)) File "C:\Users\fr3st\AppData\Local\Programs\Python\Python311\Lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\fr3st\Desktop\Screener V3\app\documents\admin.py", line 6, in <module> from .services import start_streams_documents ImportError: cannot import name 'start_streams_documents' from partially initialized module 'documents.services' (most likely due to a circular import) (C:\Users\fr3st\Desktop\Screener V3\app\documents\services.py)
问题分析
- 多进程应用未加载错误:Django启动时会加载所有应用配置,但子进程启动时不会继承这一状态,直接调用ORM会触发
Apps aren't loaded yet.。 - 循环导入问题:在模块级别调用
django.setup()会触发Django自动扫描admin模块,而admin模块又导入了services模块,形成services → db_request → django.setup() → admin → services的循环依赖链。
修复方案
方案1:子进程内部延迟初始化Django与导入依赖
修改services.py,将Django初始化和数据库查询的导入逻辑移到子进程执行的函数内部:
from multiprocessing import Process def stream(): # 子进程内部单独初始化Django import django django.setup() # 延迟导入避免模块加载阶段的循环依赖 from .db_request import get_all_documents docs = get_all_documents() def start_streams_documents(): pr = Process(target=stream) pr.start() pr.join()
- 子进程独立初始化Django,不依赖父进程的应用状态
- 延迟导入避免了模块加载阶段的循环引用
方案2:admin模块延迟导入services
修改admin.py,将services的导入从模块级别移到方法内部:
from .models import Document from django.http import HttpResponseRedirect from django.urls import path @admin.register(Document) class MachineAdmin(admin.ModelAdmin): list_display = ('name','text') change_list_template = 'admin/document_table_changelist.html' def get_urls(self): urls = super().get_urls() my_urls = [path('start_streams/', self.start_streams)] return my_urls + urls def start_streams(self, request): # 方法内部延迟导入,打破循环依赖 from .services import start_streams_documents start_streams_documents() return HttpResponseRedirect("../")
配合方案1的services.py修改,即可彻底解决两个问题。
关键注意事项
- 禁止在模块级别(文件顶部)调用
django.setup(),这会干扰Django的正常启动流程 - 多进程中涉及Django ORM的操作,必须在子进程内部单独初始化Django
- 延迟导入是解决Django循环依赖的常用手段,尤其适用于admin与业务服务模块之间的交互
内容的提问来源于stack exchange,提问作者Fresto
相关产品推荐
相关产品推荐

