【发布时间】:2016-07-24 00:36:05
【问题描述】:
我使用的是 Django 1.8(使用 pytest),我有以下配置:
-
default和readonly数据库由MasterSlaveRouter管理,根据它们是读取还是写入操作,将 DB 调用定向到一个连接或另一个连接。 - 在我的开发环境中,
settings.DATABASES字典中的两个条目具有相同的设置(它们只是使用不同的连接,但数据库是相同的)。 - 然而,在我的测试环境中,只有一个
default数据库。 - 每当保存模型
Foo时,我都会触发post_save信号。 - 我有一个原子操作(用
@transaction.atomic装饰)修改Foo实例并在其上调用.save()两次。由于没有将自定义using参数传递给装饰器,因此事务仅在default数据库上处于活动状态。
post_save 回调创建一个Bar 记录,其中OneToOneField 指向Foo,但仅在检查带有此foo_id 的Bar 记录是否已经存在(以避免IntegrityError )。通过执行以下查询来完成此检查:
already_exists = Bar.filter(foo=instance).exists()
第一次调用post_save 回调时可以。 Bar 记录已创建,一切正常。然而,第二次,即使这样一个Bar 实例只是在之前的Foo 保存中创建,由于过滤是一个读取操作,它是使用readonly 连接执行的,因此already_exists 最终包含值False 并触发新记录的创建,这最终会引发 IntegrityError,因为在default 连接上执行创建操作时,已经存在与该foo_id 的记录。
我尝试将 DATABASES 字典从 dev_settings 复制到 test_settings,但这破坏了许多测试。然后我阅读了override_settings 装饰器,并认为它非常适合我的情况。然而,令我惊讶的是,它没有奏效。似乎在某些时候,当应用程序启动时,DATABASES 字典(只有来自 test_settings 的default 的字典)被缓存,然后即使我更改了setting.DATABASES,新值也不再被访问.
如何正确覆盖一项特定测试的数据库配置?
【问题讨论】:
标签: django transactions pytest pytest-django