Python 为什么Django查询以检查唯一性?
tl;dr:为什么Django对INSERT的唯一性检查需要SELECT查询,我可以永久禁用它吗? 我正在努力高度优化Django应用程序,该应用程序正在写入PSQL数据库。我有一个uuid列,作为我的模型的一部分,它是一个主键。它是模型中唯一的Python 为什么Django查询以检查唯一性?,python,django,postgresql,django-models,django-database,Python,Django,Postgresql,Django Models,Django Database,tl;dr:为什么Django对INSERT的唯一性检查需要SELECT查询,我可以永久禁用它吗? 我正在努力高度优化Django应用程序,该应用程序正在写入PSQL数据库。我有一个uuid列,作为我的模型的一部分,它是一个主键。它是模型中唯一的唯一的字段 id = models.UUIDField( primary_key = True, default = uuid.uuid4, editable = False, null = False, blan
唯一的字段
id = models.UUIDField(
primary_key = True,
default = uuid.uuid4,
editable = False,
null = False,
blank = False,
help_text = 'The unique identifier of the Node.'
)
我遇到的问题是,当尝试保存新项目时,Django会在插入之前自动执行唯一性检查查询:
SELECT (1) AS "a" FROM "customer" WHERE "customer"."id" = \'1271a1c8-5f6d-4961-b2e9-5e93e450fd4e\'::uuid LIMIT 1
这将导致到数据库的额外往返。我知道该字段必须是唯一的,但Django当然已经在数据库级别配置了该字段,因此如果它尝试插入带有非唯一字段的行,就会出错
我已经实现了一种变通方法,通过在我的模型中添加以下内容来抑制查询:
def validate_unique(self, *args, **kwargs):
# Make sure that we never validate if ID is unique. Duplicates OK.
current_exclude = set(kwargs.get('exclude', []))
current_exclude.add('id')
kwargs['exclude'] = list(current_exclude)
super().validate_unique(*args, **kwargs)
这将确保从不检查id
字段的唯一性
这是可行的,我没有得到额外的查询。我还验证了,如果我尝试重新插入一个重复的UUID,我确实会在数据库作为源时出错
我的问题是:Django为什么这样做?我试图阻止Django检查惟一性,除非额外的DB往返实现了一些有价值的目的
环境:
在Django中,模型验证是与模型保存不同的步骤。看起来无论你做什么都会触发验证
有许多很好的理由将这些作为单独的步骤。一个是,与使用数据库约束相比,您可以在任意Python代码中表达更多的约束。另一个原因是,与解析非标准化数据库错误相比,它允许您生成更多的描述性错误消息。另一个原因是,有时你只是想知道某些东西是否有效,但并不想实际保存它
默认情况下,在保存它们之前,先使用Django。不过,一些Django组件,比如admin(更一般地说,ModelForms
)会触发验证
因此,您需要弄清楚在您的案例中触发验证的原因,如果这不是您想要的,请阻止它。作为参考,Django docs说:但是,select\u on\u save
尚未设置为true。因此,它似乎没有遵循默认行为。我添加了一个答案,但如果您解释了save调用的上下文,这会有所帮助。它是否来自模型形式
?您使用的是force\u insert
?谢谢!这与ModelForm无关,关于如何找出它被验证的原因有什么想法吗?编辑:对clean
和validate
的全文搜索显示,我们在基本模型类的save
覆盖中有full\u clean()
。。。看起来像一个cuplrit@CalebMac:这就解释了。注意,django不特别支持在<代码> SAVER()/<代码>上执行<代码> FuluxCudio()/代码>,许多人(包括我和这个)认为它是反模式。也就是说,如果需要,您可以覆盖validate_unique()
。当然,即使在您需要验证时,这也会阻止验证。如果您关心性能,请注意在save()
上执行full\u clean()
将导致在使用admin或ModelForms
时发生两次验证,因为它们已经调用full\u clean()
。
django==2.2.12
psycopg2-binary==2.8.5