在 pytest 为 django 设置数据库之前安装 postgresql 扩展

问题描述 投票:0回答:2

我需要为 django 项目安装 citext 扩展到我的 postgresql 数据库。对于项目本身来说,它进展顺利并且通过迁移运行得很好,但是我的 pytest 配置了选项

--no-migrations
,因此 pytest 创建数据库而不运行迁移。我怎样才能让 pytest 在创建表之前安装
citext
postgres 扩展?目前我正在

- django.db.utils.ProgrammingError: type "citext" does not exist

当 pytest 尝试创建表时

auth_users

sql = 'CREATE TABLE "auth_user" ("id" serial NOT NULL PRIMARY KEY, "password" varchar(128) NOT NULL, "last_login" timestamp ...T NULL, "is_active" boolean NOT NULL, "date_joined" timestamp with time zone NOT NULL, "email" citext NOT NULL UNIQUE)', params = None
ignored_wrapper_args = (False, {'connection': <django.contrib.gis.db.backends.postgis.base.DatabaseWrapper object at 0x7fb313bb0100>, 'cursor': <django.db.backends.utils.CursorWrapper object at 0x7fb30d9f8580>})

我尝试使用

django_db_setup
固定装置,但我不知道如何更改它,因为像这样

@pytest.fixture(scope="session")
def django_db_setup(
    request,
    django_test_environment,
    django_db_blocker,
    django_db_use_migrations,
    django_db_keepdb,
    django_db_createdb,
    django_db_modify_db_settings,
):
    """Top level fixture to ensure test databases are available"""
    from django.test.utils import setup_databases, teardown_databases

    setup_databases_args = {}

    if not django_db_use_migrations:
        from pytest_django.fixtures import _disable_native_migrations
        _disable_native_migrations()

    if django_db_keepdb and not django_db_createdb:
        setup_databases_args["keepdb"] = True

    with django_db_blocker.unblock():
        from django.db import connection
        cursor = connection.cursor()
        cursor.execute("CREATE EXTENSION IF NOT EXISTS citext;")

        db_cfg = setup_databases(
            verbosity=request.config.option.verbose,
            interactive=False,
            **setup_databases_args
        )
    def teardown_database():
        with django_db_blocker.unblock():
            try:
                teardown_databases(db_cfg, verbosity=request.config.option.verbose)
            except Exception as exc:
                request.node.warn(
                    pytest.PytestWarning(
                        "Error when trying to teardown test databases: %r" % exc
                    )
                )

    if not django_db_keepdb:
        request.addfinalizer(teardown_database)

没有帮助我

python django postgresql pytest pytest-django
2个回答
3
投票

令人烦恼的是,在设置数据库和加载适当的 postgresql 扩展之间没有适当的挂钩。您可以通过复制/修改禁用迁移的 pytest-django 代码并运行您的代码而不是上游代码来解决此问题。 @pytest.fixture(scope="session") def django_migration_disabler() -> None: """Disable migrations when running django tests. This copies/alters the behavior of pytest_django.fixtures._disable_migrations, which is called when pytest is invoked with --no-migrations. See: https://github.com/pytest-dev/pytest-django/blob/v4.5.2/pytest_django/fixtures.py#L260 We do this instead of invoking with --no-migrations because constructing the database without migrations fails to create necessary postgres extensions like citext and uuid-ossp. We then override the django_db_setup fixture and ensure that this fixture is called before the parent django_db_setup fixture. """ from django.conf import settings from django.core.management.commands import migrate from django.db import connections class DisableMigrations: def __contains__(self, item: str) -> bool: return True def __getitem__(self, item: str) -> None: return None settings.MIGRATION_MODULES = DisableMigrations() class MigrateSilentCommand(migrate.Command): def handle(self, *args, **options): options["verbosity"] = 0 database = options["database"] connection = connections[database] with connection.cursor() as cursor: cursor.execute('CREATE EXTENSION IF NOT EXISTS "citext";') return super().handle(*args, **options) migrate.Command = MigrateSilentCommand # type: ignore @pytest.fixture(scope="session") def django_db_use_migrations() -> bool: """Force pytest-django to use migrations. This is necessary because we disable migrations in the django_migration_disabler and the existing pytest-django mechanisms would override our disabling mechanism with their own, which would fail to create the necessary extensions in postgres. """ return True @pytest.fixture(scope="session") def django_db_setup(django_migration_disabler, django_db_setup, django_db_blocker): """Override django_db_setup ensuring django_migration_disabler is loaded.""" pass



0
投票
django_test_environment

夹具解决了这个问题。

import pytest
from django.db import connection
from django.db.models.signals import pre_migrate
from django.apps import apps


def _pre_migration(sender, app_config, **kwargs):
    with connection.cursor() as cursor:
        cursor.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;")


@pytest.fixture(autouse=True, scope="session")
def django_test_environment(django_test_environment):
    pre_migrate.connect(_pre_migration, sender=apps.get_app_config("my_app"))

© www.soinside.com 2019 - 2024. All rights reserved.