Python 为什么Django查询以检查唯一性?

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

tl;dr:为什么Django对INSERT的唯一性检查需要SELECT查询,我可以永久禁用它吗?

我正在努力高度优化Django应用程序,该应用程序正在写入PSQL数据库。我有一个uuid列,作为我的模型的一部分,它是一个主键。它是模型中唯一的
唯一的
字段

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