Django - Предупреждение «Accessing database during app initialization is discouraged» в AppConfig.ready() после обновления
Недавно я обновил Django до последней версии, 5.1.2, и с тех пор каждый раз, когда я запускаю сервер, я получаю следующее предупреждение:
RuntimeWarning: Не рекомендуется обращаться к базе данных во время инициализации приложения. Чтобы устранить это предупреждение, избегайте выполнения запросов в AppConfig.ready() или при импорте модулей вашего приложения.
Из того, что я нашел на данный момент, мой файл apps.py вызывает это из-за операции, которую он выполняет над базой данных:
from django.apps import AppConfig
class TenantsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'tenants'
def ready(self):
self.load_additional_databases()
def load_additional_databases(self):
from django.conf import settings
from .models import DatabaseConfig
for config in DatabaseConfig.objects.all():
if config.name not in settings.DATABASES:
db_settings = settings.DATABASES['default'].copy()
db_settings.update({
'ENGINE': config.engine,
'NAME': config.database_name,
'USER': config.user,
'PASSWORD': config.password,
'HOST': config.host,
'PORT': config.port,
})
settings.DATABASES[config.name] = db_settings
В моем settings.py жестко закодированы две основные базы данных (по умолчанию и арендаторы), а остальные конфигурации должны обновляться данными из модели DatabaseConfig, когда я запускаю сервер. Проблема в том, что мне нужно именно такое поведение, но решение, которое я нашел до сих пор, заключается в использовании connection_created, которое заставляет это выполняться для каждого запроса к базе данных. Вот реализация с использованием сигнала:
def db_config(**kwargs):
from django.conf import settings
from .models import DatabaseConfig
for config in DatabaseConfig.objects.all():
if config.name not in settings.DATABASES:
db_settings = settings.DATABASES['default'].copy()
db_settings.update({
'ENGINE': config.engine,
'NAME': config.database_name,
'USER': config.user,
'PASSWORD': config.password,
'HOST': config.host,
'PORT': config.port,
})
settings.DATABASES[config.name] = db_settings
class TenantsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'tenants'
def ready(self):
connection_created.connect(db_config)
Есть ли другой способ добиться прежнего поведения в методе ready? Или действительно так плохо продолжать использовать его с предупреждением? Насколько я понял из документации, этого следует избегать, но это не обязательно плохо. В документации упоминаются методы save() и delete(), но здесь я просто обновляю файл settings.py. Любая помощь будет оценена по достоинству.
<<<Поскольку я только обновляю настройки и не вношу никаких изменений на уровне базы данных, я пришел к выводу, что в моем случае можно продолжать использовать это. Чтобы заглушить предупреждение, я добавил следующее в начало settings.py:
import warnings
warnings.filterwarnings(
'ignore',
message='Accessing the database during app initialization is discouraged',
category=RuntimeWarning
)
Просто имейте в виду, что, в зависимости от случая использования, это может быть проблематично. Для справки, вот предупреждение в документации, ссылка на которую приведена в вопросе:
Хотя вы можете обращаться к классам моделей, как описано выше, избегайте взаимодействия с базой данных в своей реализации ready(). Этот включает методы модели, выполняющие запросы (save(), delete(), методы менеджера методы и т.д.), а также необработанные SQL-запросы через django.db.connection. Ваш метод ready() будет выполняться при запуске каждой команды управления. Например, несмотря на то, что конфигурация тестовой базы данных отделена от производственных настроек, manage.py test все равно выполнит несколько запросы к вашей производственной базе данных!