Иногда возникает необходимость выполнить некую инициализацию при запуске Django-проекта. Например зарегистрировать обработчики сигналов, создать подключения к внешним сервисам и др. Поскольку в самом Django нет специального сигнала сообщающего например о том, что настройки проекта были загружены и инициализированы, то приходится прибегать к другим методам запуска своего кода.
Как правило в таких случаях для этого вставляют необходимые импорты в urls.py. Но это сработает только в случае запуска сервера или прямого импорта этих файлов. При выполнении management команд загрузка urls.py не выполняется. Ещё ситуация может осложнятся необходимостью использовать в коде инициализации настроек из django.conf.settings. В этом случае мы не можем запустить инициализацию из файла settings.py, т.к. это приведёт к циклическому импорту.
Возможным решением может быть размещение кода инициализации в __init__.py проекта, но для этого необходимо, что бы путь к settings.py был добавлен в enviroment до импорта django.conf.settings. Для себя я сделал модификацию этого способа не требующую указания пути к файлу настроек внутри __init__.py проекта (у меня это выполняется в manage.py и в wsgi.py). Вот код который я добавил в __init__.py моего Django-проекта:
Работает он следующим образом. При импорте __init__.py проекта выполняется патчинг метода LazySettings._setup() отвечающего за загрузку и инициализацию настроек проекта. При первом же обращении к настройкам они загрузятся и будет выполнена функция run_stratup_scripts(), которая ищет во всех приложениях, указанных в настройке INSTALLED_APPS, модуль с именем onstartup и импортирует, его если он там есть.
Теоретически у этого способа может быть одна проблема - он не сработает если вы умудритесь запустить какой либо код в вашем проекте, который сам или косвенно не обращается к настройкам из django.conf.settings.
Если у вас проблемы с использованием этого кода в __init__.py проекта или вы не хотите патчить код Django, то можно создать минимальное приложение (содержит только __init__.py и пустой models.py), добавить ему в __init__.py определение функции run_statrup_scripts() и её вызов. Затем добавить это приложение в INSTALLED_APPS. Но тут тоже есть один минус - приложение будет импортированно джангой уже после того как первый запрос пройдёт обработку всех Middleware (по крайней мере у меня именно так и получилось).
Как правило в таких случаях для этого вставляют необходимые импорты в urls.py. Но это сработает только в случае запуска сервера или прямого импорта этих файлов. При выполнении management команд загрузка urls.py не выполняется. Ещё ситуация может осложнятся необходимостью использовать в коде инициализации настроек из django.conf.settings. В этом случае мы не можем запустить инициализацию из файла settings.py, т.к. это приведёт к циклическому импорту.
Возможным решением может быть размещение кода инициализации в __init__.py проекта, но для этого необходимо, что бы путь к settings.py был добавлен в enviroment до импорта django.conf.settings. Для себя я сделал модификацию этого способа не требующую указания пути к файлу настроек внутри __init__.py проекта (у меня это выполняется в manage.py и в wsgi.py). Вот код который я добавил в __init__.py моего Django-проекта:
def run_statrup_scripts():
from django.conf import settings
from django.utils.importlib import import_module
from django.utils.module_loading import module_has_submodule
for app in settings.INSTALLED_APPS:
mod = import_module(app)
try:
module = '%s.onstartup' % app
import_module(module)
except:
if module_has_submodule(mod, 'onstartup'):
raise
def patch_settings():
try:
from django.conf import LazySettings
except ImportError:
return
if getattr(patch_settings, 'patched', False):
return
orig_setup = LazySettings._setup
def _setup(self):
orig_setup(self)
run_statrup_scripts()
LazySettings._setup = _setup
patch_settings.patched = True
patch_settings()
Работает он следующим образом. При импорте __init__.py проекта выполняется патчинг метода LazySettings._setup() отвечающего за загрузку и инициализацию настроек проекта. При первом же обращении к настройкам они загрузятся и будет выполнена функция run_stratup_scripts(), которая ищет во всех приложениях, указанных в настройке INSTALLED_APPS, модуль с именем onstartup и импортирует, его если он там есть.
Теоретически у этого способа может быть одна проблема - он не сработает если вы умудритесь запустить какой либо код в вашем проекте, который сам или косвенно не обращается к настройкам из django.conf.settings.
Если у вас проблемы с использованием этого кода в __init__.py проекта или вы не хотите патчить код Django, то можно создать минимальное приложение (содержит только __init__.py и пустой models.py), добавить ему в __init__.py определение функции run_statrup_scripts() и её вызов. Затем добавить это приложение в INSTALLED_APPS. Но тут тоже есть один минус - приложение будет импортированно джангой уже после того как первый запрос пройдёт обработку всех Middleware (по крайней мере у меня именно так и получилось).
а не проще запихать все что нужно исполнить до запуска проекта в bat или sh? включить окружение, выполнить кастомные команды:python manage.py --do_it_before_start_of_project with_args_and_kwargs...
ОтветитьУдалить