【问题标题】:Running Django unittests causes South migrations to duplicate tables运行 Django unittests 会导致南迁移重复表
【发布时间】:2014-05-01 13:05:16
【问题描述】:

如何防止 Django 单元测试运行 South 迁移?

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

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

果然,回溯显示 South 正在被执行:

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 的测试框架执行任何 South 组件。

我做错了什么?

编辑:我通过简单地删除南来解决这个问题:

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,我猜这不是 kosher。但是,没有 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 尝试创建它两次,导致错误。

【问题讨论】:

  • 尝试使用显式布尔值:SOUTH_TESTS_MIGRATE = FalseSKIP_SOUTH_TESTS = True
  • @stevejalim,没有变化...

标签: python django django-south django-unittest


【解决方案1】:

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

我有两个模型,其中 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'

【讨论】:

    【解决方案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. 不要像我一样愚蠢,在模型创建之前尝试访问它们。这主要意味着不要直接引用其他模型或表单领域的模型。例如

      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__() 中设置选择值。

    【讨论】:

      猜你喜欢
      • 2014-03-21
      • 2015-11-03
      • 2014-06-02
      • 2014-06-22
      • 2011-04-03
      • 1970-01-01
      • 2012-06-05
      • 2020-12-10
      相关资源
      最近更新 更多