RuntimeError: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it

Viewed 4293

I am trying to run pytest and am getting this error: RuntimeError: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.

I have the following test in test_models.py that checks if the uuid has been added to the User (it is on autoadd):

import pytest

from backendapps.core.models import User

pytestmark = pytest.mark.django_db

class TestUserModel():
    user = User.objects.create()

    assert user.uuid is not None

I also have a fixtures file called conftest.py at the root level.

import pytest

from backendapps.core.models import Org, User

@pytest.fixture(autouse=True)
def enable_db_access(db):
    pass

I then also have this pytest.ini also at the root level:

[pytest]
testpaths = backendapps
addopts = --ds=config.settings.local --reuse-db --create-db
python_files = tests.py test_*.py *_tests.py```

My test database is set to:

        'TEST': {
            'NAME': 'project_test_db',
        },

Going through other posts, here are the debug steps I have taken:

  1. add the pytestmark = pytest.mark.django_db line - I have this
  2. Check the db permissions - my user has superuser permissions
  3. Check for migration errors on your db - I migrated all my migrations to zero and reran them to check if I had any manual settings when I migrated and it was all fine.

Any thoughts on what to try or how to get a clearer error?

Full error:

―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ERROR collecting backendapps/core/tests/test_models.py ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
backendapps/core/tests/test_models.py:18: in <module>
    class TestUserModel():
backendapps/core/tests/test_models.py:27: in TestUserModel
    user = User.objects.create()
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/models/manager.py:85: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/models/query.py:447: in create
    obj.save(force_insert=True, using=self.db)
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/models/base.py:753: in save
    self.save_base(using=using, force_insert=force_insert,
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/models/base.py:790: in save_base
    updated = self._save_table(
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/models/base.py:895: in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/models/base.py:933: in _do_insert
    return manager._insert(
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/models/manager.py:85: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/models/query.py:1249: in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/models/sql/compiler.py:1395: in execute_sql
    with self.connection.cursor() as cursor:
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/utils/asyncio.py:26: in inner
    return func(*args, **kwargs)
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/backends/base/base.py:259: in cursor
    return self._cursor()
../../.local/share/virtualenvs/projectAPI-NVQT3lgx/lib/python3.8/site-packages/django/db/backends/base/base.py:235: in _cursor
    self.ensure_connection()
E   RuntimeError: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.

================================================================================= short test summary info ==================================================================================
FAILED backendapps/core/tests/test_models.py - RuntimeError: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Results (0.49s):
2 Answers

I guess this error is due to the fact that you're trying to create the User on the test object directly. Therefore, the code will be executed before the Database is setup and hence the error.
You might try to create the User in a test method:

class TestUserModel:
    def test_user_uuid_is_not_none(self):
        user = User.objects.create()
        assert user.uuid is not None

Or you could simply just run a test function

def test_user_uuid_is_not_none(self):
        user = User.objects.create()
        assert user.uuid is not None

If you need access to the User several times in your Test, create a fixture and use it in the test:

[conftest.py]
@pytest.fixture
def user() -> settings.AUTH_USER_MODEL:
    # return the UserFactory (factoryboy)
    return UserFactory()

[test_models.py]
import pytest
from django.contrib.auth import get_user_model

pytestmark = pytest.mark.django_db

User = get_user_model()


class TestUserModel:
    def test_user_uuid_is_not_none(self, user: User):
        assert user.uuid is not None

From pytest docs:

By default your tests will fail if they try to access the database. Only if you explicitly request database access will this be allowed. This encourages you to keep database-needing tests to a minimum which is a best practice since next-to-no business logic should be requiring the database. Moreover it makes it very clear what code uses the database and catches any mistakes.

The easiest solution would be to add fixture as decorator:

@pytest.mark.django_db(True)
class TestUserModel():
Related