Импорт модулей 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 first.
Последний найденный мной обходной путь - поместить все импорты django внутрь каждой использующей их функции. Например, так
def foo(bar):
from data import MyModel
print(bar)
Но это невозможно сделать, если вы хотите использовать их как указания типа в сигнатуре функции. Это также выглядит очень странно, требует много дублирующих импортов в каждой функции и не очень хорошо сочетается с некоторыми функциями автозаполнения или линтера IDE.
В завершение моего вопроса:
Как можно работать с импортом моделей django в кодовой базе, не вызывая settings.configure(), пока модели фактически не используются во время выполнения для запроса к базе данных ?
Если вы используете только MyModel для аннотации типа, вы можете использовать typing.TYPE_CHECKING.
# common.py
import typing
if typing.TYPE_CHECKING:
from data import MyModel
Это будет импортировано только во время статической проверки типов, а не во время выполнения.