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')