Объект соединений 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
Другие вопросы по тегам