Подтвердить что ты не робот

Как создать таблицу во время тестов Django с помощью managed = False

У меня есть модель с managed = False.

class SampleModel(models.Model):
    apple = models.CharField(max_length=30)
    orange = models.CharField(max_length=30)

    class Meta:
        managed = False

У меня есть unit test, который создает SampleModel, однако, когда я запускаю тест, я получаю:

DatabaseError: no such table: SAMPLE_SAMPLE_MODEL

Документы django - https://docs.djangoproject.com/en/dev/ref/models/options/#managed документируют следующее:

Для тестов, связанных с моделями с managed = False, это зависит от вас убедитесь, что правильные таблицы созданы как часть тестовой настройки.

Как я могу "создать" таблицы во время тестовой настройки? Или, альтернативно, как я могу это сделать, чтобы, когда я запускаю тесты, эта модель имеет "managed = True" в течение всего теста?

В реальном приложении эта модель фактически поддерживается представлением в базе данных. Однако во время теста я хотел бы рассматривать это как таблицу и иметь возможность вставлять там тестовые данные.

4b9b3361

Ответ 1

Прочтите этот пост в блоге: http://www.caktusgroup.com/blog/2010/09/24/simplifying-the-testing-of-unmanaged-database-models-in-django/ Подробно описывается создание тестовый бегун для неуправляемых моделей.

from django.test.simple import DjangoTestSuiteRunner


class ManagedModelTestRunner(DjangoTestSuiteRunner):
    """
    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 setup_test_environment(self, *args, **kwargs):
        from django.db.models.loading import get_models
        self.unmanaged_models = [m for m in get_models()
                                 if not m._meta.managed]
        for m in self.unmanaged_models:
            m._meta.managed = True
        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

Ответ 2

Выполнить необработанный SQL для создания таблицы в тестовой настройке:

from django.db import connection

class MyTest(unittest.TestCase):
    def setUp(self):
        connection.cursor().execute("CREATE TABLE ...")

    def tearDown(self):
        connection.cursor().execute("DROP TABLE ...")

Ответ 3

Вы можете использовать SchemaEditor в методе TestCase.setUp для явного создания моделей с параметром managed = False.

# models.py

from django.db import models


class Unmanaged(models.Model):
    foo = models.TextField()

    class Meta:
        # This model is not managed by Django
        managed = False
        db_table = 'unmanaged_table'

И в ваших тестах:

# tests.py

from django.db import connection
from django.test import TestCase

from myapp.models import Unmanaged


class ModelsTestCase(TestCase):
    def setUp(self):
        super().setUp()

        with connection.schema_editor() as schema_editor:
            schema_editor.create_model(Unmanaged)

            if Unmanaged._meta.db_table not in connection.introspection.table_names():
                raise ValueError("Table '{table_name}' is missing in test database.".format(table_name=Unmanaged._meta.db_table))

    def tearDown(self):
        super().tearDown()

        with connection.schema_editor() as schema_editor:
            schema_editor.delete_model(Unmanaged)

    def test_unmanaged_model(self):
        with self.assertNumQueries(num=3):
            self.assertEqual(0, Unmanaged.objects.all().count())
            Unmanaged.objects.create()
            self.assertEqual(1, Unmanaged.objects.all().count())

Ответ 4

Создайте свой собственный тестовый бегун, используя это:

from django.test.simple import DjangoTestSuiteRunner

class NoDbTestRunner(DjangoTestSuiteRunner):
  """ A test runner to test without database creation """

  def setup_databases(self, **kwargs):
    """ Override the database creation defined in parent class """
    #set manage=True for that specific database on here

Затем в ваших настройках добавьте этот класс в TEST_RUNNER.

Ответ 5

Быстрое исправление, если у вас нет много неуправляемых таблиц:

Сначала добавьте новую переменную в настройки.

# settings.py
import sys
UNDER_TEST = (len(sys.argv) > 1 and sys.argv[1] == 'test')

то в моделях

# models.py
from django.conf import settings

class SampleModel(models.Model):
    apple = models.CharField(max_length=30)
    orange = models.CharField(max_length=30)

    class Meta:
        managed = getattr(settings, 'UNDER_TEST', False)

Ответ 6

Хорошее решение для подключения к сети. Просто вставьте это перед определением тестового класса. (примечание: используется django 1.8)

from django.db.models.loading import get_models

def change_managed_settings_just_for_tests():
  """django model managed bit needs to be switched for tests."""    

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

change_managed_settings_just_for_tests()

Ответ 7

Просто добавьте: django.db.models.loading.get_models будет удален в Django 1.9 (см. https://github.com/BertrandBordage/django-cachalot/issues/33).

Ниже приведен обновленный вариант для Django 1.10:

class UnManagedModelTestRunner(DiscoverRunner):
    '''
    Test runner that automatically makes all unmanaged models in your Django
    project managed for the duration of the test run.
    Many thanks to the Caktus Group 
    '''

    def setup_test_environment(self, *args, **kwargs):
        from django.apps  import apps
        self.unmanaged_models = [m for m in apps.get_models() if not m._meta.managed]
        for m in self.unmanaged_models:
            m._meta.managed = True
        super(UnManagedModelTestRunner, self).setup_test_environment(*args, **kwargs)

    def teardown_test_environment(self, *args, **kwargs):
        super(UnManagedModelTestRunner, self).teardown_test_environment(*args, **kwargs)
        # reset unmanaged models
        for m in self.unmanaged_models:
            m._meta.managed = False 

Обратите внимание, что вам также необходимо пройти миграцию (см. Тестирование приложения django с несколькими устаревшими базами данных)

MIGRATION_MODULES = {
    'news': 'news.test_migrations',
    'economist': 'economist.test_migrations'
}