在未配置设置的情况下导入django模块



考虑以下简单场景。给定文件common.py

from data import MyModel    # This is a Model inheriting django.db.models.Model
def foo(bar: MyModel):
print(bar)
def other_func():
pass

给定文件main.py,使用其中一个通用函数,但不使用另一个依赖于django的函数。

import common
from django.conf import settings
if __name__ == "__main__":
config_file = sys.argv[1]   # This would be argparser in real life scenario
settings.configure(....config_file...)
common.other_func()

这种格式是我认为大多数主要函数的样子,因为设置通常取决于环境变量、配置文件或命令行参数。

我无法运行此代码,因为每当导入django模型时,它都会尝试加载设置并访问数据库。出现以下错误:

File "models.py", line 33, in <module>
class MyModel(models.Model):
File "django/db/models/base.py", line 108, in __new__
app_config = apps.get_containing_app_config(module)
File "django/apps/registry.py", line 253, in get_containing_app_config
self.check_apps_ready()
File "django/apps/registry.py", line 135, in check_apps_ready
settings.INSTALLED_APPS
File "django/conf/__init__.py", line 84, in __getattr__
self._setup(name)
File "django/conf/__init__.py", line 65, in _setup
raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: 
Requested setting INSTALLED_APPS, but settings are not configured. 
You must either define the environment variable DJANGO_SETTINGS_MODULE 
or call settings.configure() before accessing settings.

下一次尝试,将settings.configure移动到main.py、内的导入上方

from django.conf import settings
settings.configure(.....)
import common

这是有效的,但它会感染整个代码库,使得无法从任何其他模块和单元测试中import common。除非保证每个潜在入口点也首先调用settings.configure

我找到的最后一个解决方法是将所有django导入放入使用它们的每个函数中。像这个

def foo(bar):
from data import MyModel
print(bar)

但是,如果您想将它们用作函数签名上的类型注释,则这是不可能的。它看起来也很奇怪,在每个函数中都需要大量重复导入,并且与一些IDE自动完成或linter功能配合不好。


因此,总结我的问题:

如何在代码库中处理django模型导入,而不必调用settings.configure(),直到模型在运行时实际用于查询数据库?

如果类型注释仅使用MyModel,则可以使用typing.TYPE_CHECKING

# common.py
import typing
if typing.TYPE_CHECKING:
from data import MyModel

这将只在静态类型检查期间导入,而不是在运行时导入。

最新更新