如何在Django测试中使用managed = False创建表格

问题描述:

我有一个托管= False的模型。如何在Django测试中使用managed = False创建表格

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

    class Meta: 
     managed = False 

我有创造的SampleModel单元测试,但是当我运行测试,我得到:

DatabaseError: no such table: SAMPLE_SAMPLE_MODEL 

Django文档 - https://docs.djangoproject.com/en/dev/ref/models/options/#managed介绍以下:

对于测试涉及托管= False的模型,则由您决定 确保将正确的表创建为测试设置的一部分。

如何在测试设置过程中真正“创建”表格?或者,我该如何做到这一点,以便在运行测试时,该模型在测试期间的“managed = True”?

在实际应用中,该模型实际上由数据库中的视图支持。然而,在测试过程中,我想把它作为一个表格,并且能够在其中插入测试数据。

看看这个博客文章:http://www.caktusgroup.com/blog/2010/09/24/simplifying-the-testing-of-unmanaged-database-models-in-django/它详细描述了非托管模型的测试运行器的创建。

+1

它不适用于Django 1.11(因为它将使用迁移来创建测试数据库,并且在您的模型定义将设置'managed = False')。在https://*.com/a/37060122/462655中提出的解决方案适用于Django 1.11 – msonsona

+0

FWIW这也不适用于Django 1.10.7(也可能是整个1.10.x系列,但我不确定) 。 –

+0

可以在https://dev.to/patrnk/testing-against-unmanaged-models-in-django上获得原始测试跑步者创意的更新 – shadi

执行原始的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 ...") 
+0

可以使用dump命令只包括表定义,并在此答案的'setUp()'方法中使用它。例如,在MySQL情况下,该命令可能类似于'mysqldump --no-data databasename'。 –

+0

每个单独测试的'CREATE'和'DROP'表都很慢。模式在测试之间永远不会改变。 –

使用此创建自己的测试运行:

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。

速战速决,如果你没有太多的非托管表:

首先添加一个新的变量来设置。

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

尼斯即插即用解决方案。只需在测试类定义之前粘贴它即可。 (注:使用的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() 

我想补充: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 

注意你也需要照顾迁移(见Testing django application with several legacy databases

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