Импорт модулей 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

Это будет импортировано только во время статической проверки типов, а не во время выполнения.

Вернуться на верх