python - 如何在 django 单元测试中重现以下 IntegrityError?
问题描述
我有两个模型“问题”和“字体”。在这些“问题”中是不可删除的模型。Question 引用了Font。
所以如果一个字体被删除,那么有问题的字体引用将被设置为无,如果一个问题被删除,那么由于问题是一个不可删除的模型,它不会从数据库中删除,它的活动字段将被设置为假,所以它不能通过 Django 的“对象”模型管理器进行查询。在这种情况下,如果我删除一个问题,然后,如果我尝试删除字体,它会抛出“IntegrityError”,因为软删除的问题仍然引用该字体。
问题是我无法在单元测试中重现这一点。在单元测试中,字体被优雅地删除。在前端,我得到以下信息。
update or delete on table "custom_fonts_customfont" violates foreign key constraint "font_id_refs_id_794a5361" on table "questions_question"
DETAIL: Key (id)=(1026) is still referenced from table "questions_question".
我尝试使用 Django 的 Transaction 测试用例,我还确保测试用例中的问题被软删除,并通过使用 Django 的“未过滤”模型管理器确认问题对字体的引用。
class Question(ExtendedOrderedModel, NonDeletableModel):
font = models.ForeignKey('custom_fonts.CustomFont', null=True, on_delete=models.SET_NULL)
这是我的测试用例
def test_font_deletion_after_question_deletion_(self):
self.question.font = CustomFont.objects.create(
name='roboto', font_type='truetype', path='font.ttf', created_by=self.owner
)
self.question.save()
self.question.delete()
CustomFont.objects.all().delete() # This should raise an error but it is not raising
print(Question.objects.all()) # []
print(Question.unfiltered.first().font_id) # 1
解决方案
最后,我找到了原因。这是因为
在 Postgresql 中,约束设置为 DEFERRABLE INITIALLY DEFERRED。这导致它仅在提交事务时检查这些约束。(这也可能会影响 Oracle 后端,基于快速搜索。)这会导致 TestCase 出现问题:由于它们从未提交,因此永远不会触发许多约束违规。
在我的测试用例中添加以下几行对我有帮助。
cursor = connection.cursor()
cursor.execute('SET CONSTRAINTS ALL IMMEDIATE')
推荐阅读
- javascript - 在保存之前将值从选项列表复制到文本字段?
- java - selenium - 截屏时“接收来自渲染器的消息超时:10.000”
- reactjs - ReactJS 错误 - 实现绝对导入后“TypeError: Object(...) is not a function”
- typo3 - 需要清理 TYPO3 存储库功能中的用户输入吗?
- swift - 将 Text() 添加到 VStack 时,SwiftUI“调用中位置 #11、#12 的额外参数”
- javascript - 数据不会传输到 Angular 组件
- vba - Excel VBA将索引公式分配给变量
- php - 在对象中搜索元键并获取值
- amazon-web-services - EKS Kubernetes 出站流量
- html - 如何在输入字段顶部放置加号