Объект соединений Django не видит таблицы второй базы данных во время тестирования с помощью pytest-django
Итог: мой объект соединений django не видит табличных отношений второй базы данных во время тестирования с помощью pytest-django.
Обзор: у меня проблема с тем, что мой объект соединений django, кажется, получает неверную информацию базы данных. Я наткнулся на эту проблему, когда запрашивал таблицу в БД "клиентов", и Джанго сказал мне, что связь не существует. С помощью базы данных settings.py был настроен раздел, как показано ниже:
DATABASES = {
'default': {
'NAME': 'user_data',
'ENGINE': 'django.db.backends.postgres',
'USER': 'postgres_1',
'PASSWORD': 'superS3cret'
},
'customers': {
'NAME': 'customer_data',
'ENGINE': 'django.db.backends.postgres',
'USER': 'postgres_1',
'PASSWORD': 'superS3cret'
}
}
Оба указателя ниже получают информацию из базы данных "по умолчанию", когда я запускаю "pytest" в каталоге с:
sql = """SELECT table_name FROM information_schema.tables WHERE table_nameschema='public'"""
default = connections["default"].cursor()
default.execute(sql)
raw_data = default.fetchall()
sql_columns = [col[0] for col in default.description]
df1 = pd.DataFrame(raw_data, columns=sql_columns)
customers = connections["customers"].cursor()
customers.execute(sql)
raw_data = customers.fetchall()
sql_columns = [col[0] for col in customers.description]
df2 = pd.DataFrame(raw_data, columns=sql_columns)
Результаты df1 и df2 абсолютно одинаковы: только имена таблиц в базе данных "по умолчанию".
Это происходит с pytest-django и использованием второй базы данных Postgres, но только иногда.
В приведенном выше запросе я ожидаю, что df1 и df2 будут разными, поскольку базы данных по умолчанию и клиенты различаются. Тем не менее, иногда курсор соединений не может "видеть" всю информацию во второй базе данных.
Странно то, что настройки подключения отображаются по-разному при печати:
print(connections.databases)
объект "соединений" содержит две разные БД, но одна из них - "тестовая" БД. Оператор print выдает словарь, но обратите внимание на "test_customers":
(pdb) { 'default': { <conn info>}, 'test_customers': { <conn info> } }
Кажется, что Django пытается установить тестовую базу данных, не проходит и не проходит тесты, потому что таблицы в test_customers не существуют так же, как в рабочей среде.
Как мне это исправить, чтобы pytest-django ВСЕГДА видел таблицы во второй базе данных (клиенты) во время тестирования? Я делаю что-то не так с настройкой и разборкой БД?
ОБНОВЛЕНИЕ: Чтение документов pytest-django по созданию / повторному использованию БД указало мне правильное направление. Тем не менее, я немного обеспокоен этим разделом документов:
В настоящее время pytest-django специально не поддерживает поддержку нескольких баз данных Django. Однако вы можете использовать обычные экземпляры Django TestCase, чтобы использовать его поддержку multi_db.
Если у вас есть какие-либо идеи относительно лучшего API для поддержки нескольких баз данных непосредственно в pytest-django, пожалуйста, свяжитесь с нами, мы заинтересованы в том, чтобы в конечном итоге поддержать это, но не уверены в простом следовании подходу Django.
1 ответ
pytest-django
не поддерживает несколько баз данных. Когда я экспериментировал с несколькими базами данных и параметрами --reuse-db
/ --create-db
в результате иногда это работает (все базы данных созданы и могут использоваться правильно), а иногда не работает (либо база данных не создана, либо Django жалуется, что база данных уже существует).
ИМХО есть два варианта: 1) не использовать pytest с Django; 2) упростить ваши тесты, чтобы вам не нужно несколько баз данных. Для варианта 2) Я использую эту настройку:
нормальный settings
:
DATABASES = {
'default': ...,
'secondary': ...,
}
pytest.ini
:
[pytest]
...
DJANGO_SETTINGS_MODULE=my_app.settings.test
...
test.py
:
# Import all from normal settings
from .base import *
DATABASES.pop('secondary')
# This will route all queries and migrations to the default DB
DATABASE_ROUTERS = []
В test_settings.py -> патч обезьяны
from django.db.models.query import QuerySet, RawQuerySet
queryset_using = QuerySet.using
raw_queryset_using = RawQuerySet.using
def new_queryset_using(self, alias):
return queryset_using(self, 'default')
def new_raw_queryset_using(self, alias):
return raw_queryset_using(self, 'default')
QuerySet.using = new_queryset_using
RawQuerySet.using = new_raw_queryset_using