Your table is unmanaged (managed = False
) so it does not get created automatically during migration or testing.
- If your table is supposed to get created during migration, just remove the
managed = False
line
- If your table is a view or legacy table that is not supposed to get created during migration, you need to make the model managed during testing.
If 2, and you're using simple manage.py test
, the best solution I've found is to add a test runner that modifies the managed flag on any unmanaged models. Mine looks like this in a runners.py file:
# Credit:
# http://birdhouse.org/blog/2015/03/25/django-unit-tests-against-unmanaged-databases/
# https://www.caktusgroup.com/blog/2010/09/24/simplifying-the-testing-of-unmanaged-database-models-in-django/
from smapi.settings import *
from django.test.runner import DiscoverRunner
class ManagedModelTestRunner(DiscoverRunner):
"""
Test runner that automatically makes all unmanaged models in your Django
project managed for the duration of the test run, so that one doesn't need
to execute the SQL manually to create them.
"""
def __init__(self, **kwargs):
from django.apps import apps
super(ManagedModelTestRunner, self).__init__(**kwargs)
# for a in apps.get_apps():
# print("Found app %s" % (a))
# NOTE: apps must be registered in INSTALLED_APPS in settings.py before their models appear here
all_models = apps.get_models()
# for m in all_models:
# print("Found model %s - Managed:%s" % (m, m._meta.managed))
self.unmanaged_models = [m for m in all_models if not m._meta.managed]
def setup_test_environment(self, *args, **kwargs):
for m in self.unmanaged_models:
m._meta.managed = True
# print("Modifying model %s to be managed for testing - Managed:%s" % (m, m._meta.managed))
super(ManagedModelTestRunner, self).setup_test_environment(*args, **kwargs)
def teardown_test_environment(self, *args, **kwargs):
super(ManagedModelTestRunner, self).teardown_test_environment(*args, **kwargs)
# reset unmanaged models
for m in self.unmanaged_models:
m._meta.managed = False
# print("Resetting model %s to be unmanaged - Managed:%s" % (m, m._meta.managed))
It is activated by adding this line to settings.py:
# Set Django's test runner to the custom class defined in runners.py
TEST_RUNNER = '<project name>.runners.ManagedModelTestRunner'
Finally, I'm here today because we started using pytest for testing and the solution above stopped working. After a bunch of searching, I discovered a fix in the comments to one of the pages credited in the sample above (source, credit to Jan Murre)
Thanks for the trick. Because I am using pytest-django I had to find
out how to do this my way.
pytest-django uses fixtures. There is already a fixture that does the
setup_test_environment() call.
So, we need a fixture that comes before that, to set the
'_meta.managed'. It seems that automatic fixtures are executed in
alphabetical order, so to come before the pytest-django fixture (that
has a name starting with '_django'), the name of our fixture starts
with a '__'.
@pytest.fixture(autouse=True, scope='session')
def __make_unmanaged_managed():
from django.db.models.loading import get_models
unmanaged_models = [m for m in get_models() if not m._meta.managed]
for m in unmanaged_models:
m._meta.managed = True
We put the above code in conftest.py and our tests started working again.