Django test tables are not being created
Asked Answered
I

4

8

I'm trying to write test cases for my django project but when I run "$ ./manage.py test" command its creating test database but its not creating any tables and I'm getting an error that table does't exists. Any suggestions are welcome. Here is my model which i have created through "./manage.py inspectdb > models.py"

class MyCustomModel(models.Model):
    name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)

    class Meta:
       managed = False
       db_table = 'MY_TABLE'
Indecision answered 22/6, 2015 at 6:40 Comment(2)
Possible duplicate of Django connections object does not see the tables of a second database during testing with pytest-djangoIndividuation
pytest-django does not support multiple dbs: #49836420Individuation
H
11

pytest create table for unmanaged model during testing

add --nomigrations to your pytest.ini or setup.cfg - wherever your pytest settings live:

[pytest]
addopts = --nomigrations

and add this to your top-level conftest.py

@pytest.fixture(autouse=True, scope="session")
def django_test_environment(django_test_environment):
    from django.apps import apps

    get_models = apps.get_models

    for m in [m for m in get_models() if not m._meta.managed]:
        m._meta.managed = True

It will do the magic

Homogenous answered 14/6, 2018 at 3:7 Comment(3)
In my case, the autouser argument was throwing an error so I removed it and it worked.Yurt
This might seem like a n00b question, but where does the conftest.py go? Is it in the same directory as all the other django settings?Lahr
Actually, don't answer the above, I think I figured it out.Lahr
T
8

Your table is unmanaged (managed = False) so it does not get created automatically during migration or testing.

  1. If your table is supposed to get created during migration, just remove the managed = False line
  2. 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.

Therapist answered 7/7, 2016 at 15:58 Comment(1)
This is the analogous code for Django 1.9 and beyond, thought it does not work for me: from django.apps.apps import get_modelsSpringtail
A
0

Do you have migrations? Run python manage.py makemigrations, the DB that's buildt during a test run uses them.

Academician answered 23/6, 2015 at 14:31 Comment(0)
G
0

You need to use:

./manage.py syncdb

This is replace by

./django-admin migrate

From django 1.7

Gravel answered 23/6, 2015 at 14:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.