运行Django单元测试会导致South迁移重复表

时间:2014-05-01 13:05:17

标签: python django django-south django-unittest

你如何阻止Django单元测试运行南迁移?

我有一个自定义的Django应用程序myapp,我尝试使用manage.py test myapp进行测试但是当我运行它时出现错误:

django.db.utils.OperationalError: table "myapp_mymodel" already exists

果然,追溯显示南方正在被执行:

File "/usr/local/myproject/.env/local/lib/python2.7/site-packages/south/management/commands/test.py", line 8, in handle
super(Command, self).handle(*args, **kwargs)

但是,在我的设置中,我已指定:

SOUTH_TESTS_MIGRATE = 0
SKIP_SOUTH_TESTS = 1

我认为应该阻止Django的测试框架执行任何南方组件。

我做错了什么?

编辑:我只是通过以下方式解决了这个问题:

if 'test' in sys.argv:
    INSTALLED_APPS.remove('south')

然而,我得到了:

ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the NAME value.

对于我的测试数据库设置,我使用的是:

DATABASES = {
    'default':{
        'ENGINE': 'django.db.backends.sqlite3'
    }
}

在Django 1.4中运行良好。现在我使用Django 1.5,我猜这不是犹太人。但是,没有NAME值,我认为它可以修复它。他们都报告我的桌子都没有。我试过了:

DATABASES = {
    'default':{
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '/dev/shm/test.db',
        'TEST_NAME': '/dev/shm/test.db',
    }
}


DATABASES = {
    'default':{
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': ':memory:',
        'TEST_NAME': ':memory:',
    }
}

DATABASES = {
    'default':{
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(os.path.dirname(__file__), 'test.db'),
        'TEST_NAME': os.path.join(os.path.dirname(__file__), 'test.db'),
    }
}

每个似乎都创建了一个物理test.db文件,我不明白,因为单元测试应该在内存中运行。它永远不应该保存到磁盘上。据推测,它在创建文件之后但在执行实际单元测试之前未能运行syncdb。我该如何解决这个问题?

编辑:我发现,在我的一个表单中,我通过直接查询模型来填充字段选择(而我应该在表单内部 init 中执行此操作),因此,当Django的测试框架导入我的模型时,它试图在创建sqlite3数据库之前读取该表。我解决了这个问题,但现在我收到了错误:

DatabaseError: table "myapp_mythroughmodel" already exists

所以我回到原点,即使它抛出的异常类型与最初不同。

编辑:我通过模型定义了重复,导致Django尝试创建它两次,导致错误。

2 个答案:

答案 0 :(得分:3)

这也发生在遗留代码上,但出于另一个原因。

我有两个模型,db_table引用相同的db表。 我知道那是愚蠢的,但这不是我的错)

我从来没有在互联网上找到任何可以帮助我的东西。 我被详细设置为3(manage.py test -v 3)保存 希望这对任何人都有帮助。

class Bla1(Model):
    some_column = ...
    class Meta:
        db_table = 'some_table'

class Bla2(Model):
    some_column = ...
    class Meta:
        db_table = 'some_table'

答案 1 :(得分:2)

此错误是几个问题的结果。我会在这里总结他们,以帮助那些可能偶然发现这一点的人。

  1. 确保您的settings.DATABASES设置正确。 Django的文档提到使用TEST_NAME,但为了清楚起见,我发现检查test命令并覆盖所有内容更容易。例如在我的settings.py的底部,我有:

    if 'test' in sys.argv:
        DATABASES = {
            'default':{
                'ENGINE': 'django.db.backends.sqlite3',
                'NAME': ':memory:',
            },
        }
    

    除非你有充分的理由,总是使用:memory:来确保它在内存中运行,并且不会创建一个会陷入磁盘的物理文件。由于一些奇怪的原因,SO上的许多其他答案建议指定test.db文件的文字路径进行测试。这是一个可怕的建议。

  2. 除非你想测试South和/或你的South迁移,否则禁用South,因为它只会使事情变得复杂:

    SOUTH_TESTS_MIGRATE = False
    SKIP_SOUTH_TESTS = True
    
  3. 不要像我一样愚蠢,并尝试在模型创建之前访问它们。这主要意味着不直接参考其他模型或表格领域的模型。 e.g。

    class MyForm(forms.Form):
    
        somefield = forms.ChoiceField(
            required=True,
            choices=[(_.id, _.name) for _ in OtherModel.objects.filter(criteria=blah)],
        )
    

    这可能适用于数据库已经存在的代码,但是当它尝试加载测试时会破坏Django的unittest框架,这会加载你的models.py和forms.py,导致它读取一个没有的表。存在。相反,请在表单__init__()

  4. 中设置选项值