访问方法“gin”不存在操作符类“gin_trgm_ops”

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

psycopg2.errors.UndefinedObject: operator class "gin_trgm_ops" does not exist for access method "gin"

大家好,这是当我尝试在我的项目上运行 pytest 时的全部消息,该项目是用 Python/Django + db 编写的 postgresql 并且全部位于 docker 中。

我使用 django-cookiecutter 模板在 docker 上构建了一个项目,所有设置都是默认的。我将 gin 索引放入我的字符串字段之一,迁移成功运行,

pg_trgm
扩展已成功创建,但是如果我尝试使用 pytest 测试我的项目,我会收到此错误。

这是我的

pytest.ini

[pytest]
DJANGO_SETTINGS_MODULE = config.settings.test

这是我的测试设置文件的数据库配置:

test.py

DATABASES['test'] = { # noqa
    'ENGINE': 'django.contrib.gis.db.backends.postgis',
    'NAME': 'test',
    'PASSWORD': 'test',
    'USER': 'test',
    'HOST': 'localhost',
    'PORT': 5454,
}

这是迁移的一部分,它创建扩展

pg_trgm
并将索引放入给定的字段

migrations.AddIndex(
            model_name='<model_name>',
            index=django.contrib.postgres.indexes.GinIndex(fields=['field_name'], name='field_name_gin_idx', opclasses=['gin_trgm_ops']),
        ),

这是我得到的整个回溯:

self = <django.db.backends.utils.CursorWrapper object at 0xffff7244dbb0>
sql = 'CREATE INDEX "bank_name_gin_idx" ON "financing_graincreditagrobankworksheet" USING gin ("bank_name" gin_trgm_ops)', params = None
ignored_wrapper_args = (False, {'connection': <django.contrib.gis.db.backends.postgis.base.DatabaseWrapper object at 0xffff7d096b80>, 'cursor': <django.db.backends.utils.CursorWrapper object at 0xffff7244dbb0>})

    def _execute(self, sql, params, *ignored_wrapper_args):
        self.db.validate_no_broken_transaction()
        with self.db.wrap_database_errors:
            if params is None:
                # params default might be backend specific.
>               return self.cursor.execute(sql)
E               psycopg2.errors.UndefinedObject: operator class "gin_trgm_ops" does not exist for access method "gin"

/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py:82: UndefinedObject

The above exception was the direct cause of the following exception:

request = <SubRequest '_django_setup_unittest' for <TestCaseFunction test_correct_insurance_company_name>>
django_db_blocker = <pytest_django.plugin._DatabaseBlocker object at 0xffff7fe702b0>

    @pytest.fixture(autouse=True, scope="class")
    def _django_setup_unittest(
        request,
        django_db_blocker: "_DatabaseBlocker",
    ) -> Generator[None, None, None]:
        """Setup a django unittest, internal to pytest-django."""
        if not django_settings_is_configured() or not is_django_unittest(request):
            yield
            return
    
        # Fix/patch pytest.
        # Before pytest 5.4: https://github.com/pytest-dev/pytest/issues/5991
        # After pytest 5.4: https://github.com/pytest-dev/pytest-django/issues/824
        from _pytest.unittest import TestCaseFunction
        original_runtest = TestCaseFunction.runtest
    
        def non_debugging_runtest(self) -> None:
            self._testcase(result=self)
    
        try:
            TestCaseFunction.runtest = non_debugging_runtest  # type: ignore[assignment]
    
>           request.getfixturevalue("django_db_setup")

/usr/local/lib/python3.9/site-packages/pytest_django/plugin.py:490: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/local/lib/python3.9/site-packages/pytest_django/fixtures.py:122: in django_db_setup
    db_cfg = setup_databases(
/usr/local/lib/python3.9/site-packages/django/test/utils.py:179: in setup_databases
    connection.creation.create_test_db(
/usr/local/lib/python3.9/site-packages/django/db/backends/base/creation.py:74: in create_test_db
    call_command(
/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py:181: in call_command
    return command.execute(*args, **defaults)
/usr/local/lib/python3.9/site-packages/django/core/management/base.py:398: in execute
    output = self.handle(*args, **options)
/usr/local/lib/python3.9/site-packages/django/core/management/base.py:89: in wrapped
    res = handle_func(*args, **kwargs)
/usr/local/lib/python3.9/site-packages/django/core/management/commands/migrate.py:244: in handle
    post_migrate_state = executor.migrate(
/usr/local/lib/python3.9/site-packages/django/db/migrations/executor.py:117: in migrate
    state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
/usr/local/lib/python3.9/site-packages/django/db/migrations/executor.py:147: in _migrate_all_forwards
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
/usr/local/lib/python3.9/site-packages/django/db/migrations/executor.py:227: in apply_migration
    state = migration.apply(state, schema_editor)
/usr/local/lib/python3.9/site-packages/django/db/migrations/migration.py:126: in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
/usr/local/lib/python3.9/site-packages/django/db/migrations/operations/models.py:761: in database_forwards
    schema_editor.add_index(model, self.index)
/usr/local/lib/python3.9/site-packages/django/db/backends/postgresql/schema.py:218: in add_index
    self.execute(index.create_sql(model, self, concurrently=concurrently), params=None)
/usr/local/lib/python3.9/site-packages/django/db/backends/base/schema.py:145: in execute
    cursor.execute(sql, params)
/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py:66: in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py:75: in _execute_with_wrappers
    return executor(sql, params, many, context)
/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py:84: in _execute
    return self.cursor.execute(sql, params)
/usr/local/lib/python3.9/site-packages/django/db/utils.py:90: in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <django.db.backends.utils.CursorWrapper object at 0xffff7244dbb0>
sql = 'CREATE INDEX "bank_name_gin_idx" ON "financing_graincreditagrobankworksheet" USING gin ("bank_name" gin_trgm_ops)', params = None
ignored_wrapper_args = (False, {'connection': <django.contrib.gis.db.backends.postgis.base.DatabaseWrapper object at 0xffff7d096b80>, 'cursor': <django.db.backends.utils.CursorWrapper object at 0xffff7244dbb0>})

    def _execute(self, sql, params, *ignored_wrapper_args):
        self.db.validate_no_broken_transaction()
        with self.db.wrap_database_errors:
            if params is None:
                # params default might be backend specific.
>               return self.cursor.execute(sql)
E               django.db.utils.ProgrammingError: operator class "gin_trgm_ops" does not exist for access method "gin"

/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py:82: ProgrammingError

我想用 pytest 运行测试并得到这个问题,实际上在项目运行时不会引起任何问题,gin 索引实际上正在工作。但只有当我运行测试时,无论它的 django 是

manage.py test
还是
pytest
,它都会失败并出现上述错误。如果我注释掉应该生成索引的迁移部分,它就可以工作。

python django indexing pytest-django pg-trgm
1个回答
0
投票

尝试添加到您的迁移中:

from django.contrib.postgres.operations import TrigramExtension

operations = [
    TrigramExtension(),
    ...
]
© www.soinside.com 2019 - 2024. All rights reserved.