Pytest + django выдают ошибку базы данных, когда область применения приспособления имеет значение 'module'

У меня внутри conftest.py

следующее
@pytest.mark.django_db
@pytest.fixture(scope='module')
def thing():
    print('sleeping')  # represents a very expensive function that i want to only ever once once per module
    Thing.objects.create(thing='hello')
    Thing.objects.create(thing='hello')
    Thing.objects.create(thing='hello')

Inside tests.py

@pytest.mark.django_db
def test_thing(thing):
    assert models.Thing.objects.count() > 1

@pytest.mark.django_db
def test_thing2(thing):
    assert models.Thing.objects.count() > 1


@pytest.mark.django_db
@pytest.mark.usefixtures('thing')
def test_thing3():
    assert models.Thing.objects.count() > 1

Все три теста выдают одну и ту же ошибку: RuntimeError: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.

Я пробовал использовать scope='session' / scope='class' / scope='package' / scope='module' - единственное, что работает, это `scope='function', что противоречит цели того, чего я пытаюсь достичь. Я хочу иметь возможность создавать все эти элементы ОДИН раз на модуль, а не один раз на тест.

Примечание: Я столкнулся с этой проблемой с большой базой кода и создал новый проект django с одним приложением, чтобы проверить и узнать, была ли проблема в существующем тестовом коде, и он также не сработал на отдельном тесте. Проверял и с postgres, и с sqlite; не похоже на проблему с базой данных.

Не то чтобы это имело значение, но models.py

class Thing(models.Model):
    thing = models.CharField(max_length=100)

Оказывается, это известное ограничение, и оно немного задокументировано здесь. Если вы хотите решить эту проблему и избавиться от этой ошибки:

@pytest.mark.django_db
@pytest.fixture(scope='module')
def thing(django_db_setup, django_db_blocker):
    del django_db_setup  # Cannot be used with usefixtures(..) it won't work
    with django_db_blocker.unblock():
        print('sleeping')
        Thing.objects.create(thing='hello')
        Thing.objects.create(thing='hello')
        Thing.objects.create(thing='hello')
        Thing.objects.create(thing='hello')
        yield

Вместо этого вы можете запросить db фикстуру в фикстуре. Это описано в docs в первой заметке.

Если вы хотите получить доступ к базе данных Django внутри фикстуры, этот маркер может помочь или не помочь, даже если функция, запрашивающая вашу фикстуру, имеет этот маркер, в зависимости от порядка выполнения фикстуры в pytest. Чтобы получить доступ к базе данных в фикстуре, рекомендуется, чтобы фикстура явно запросила один из фикстуров db, transactional_db, django_db_reset_sequences или django_db_serialized_rollback. ( подчеркивание мое)

# conftest.py

@pytest.fixture(scope='module')
def thing(db):  # Use "db" fixture
    print('sleeping')  # represents a very expensive function that i want to only ever once once per module
    Thing.objects.create(thing='hello')
    Thing.objects.create(thing='hello')
    Thing.objects.create(thing='hello')
Вернуться на верх