问题描述
当我的模型需要特殊验证时,我通常首先考虑db约束以完全确保数据库的完整性,但是我发现这种方法存在一些问题。我通常使用UniqueConstraints,例如:
models.UniqueConstraint(
fields=('author','title'),name='valid_unique_author_title',),
,它们之所以工作良好,是因为表单和序列化程序会捕获错误并显示类似Post with this Author and Title already exists.
的错误,但是UniqueConstraint发生的情况具有类似条件
models.UniqueConstraint(
fields=('author',condition=models.Q(title='title1'),name='valid_unique_title1_author_title',
与预期的相反,它们抛出一个完整性错误,该错误不会被表单和序列化器(DRF)捕获,从而导致HTTP响应以500作为状态码,仅通过添加条件便不再捕获该错误。第一个问题,我必须修改所有具有检查约束或具有唯一约束的表格和序列化程序,并带有捕获完整性错误的条件吗?
最后,相同的CheckConstraints也是如此:
models.CheckConstraint(
check=~models.Q(title='forbidden_title'),name='valid_forbidden_title'
),
上述示例有所不同,我发现了两种约束条件:
- 对比赛条件不敏感。检查约束,用于验证
forbidden_title
的标题是否不同。 - 容易受到比赛条件的影响。第二个UniqueConstraint,用于验证当标题等于
title1
时作者是否还有其他标题相同的帖子。我可以在表格或序列化器中验证约束,但仍可能出现竞争条件。
我发现了一些有关如何管理此类错误的评论,并且大多数仅以序列化程序的形式进行验证。第二个约束条件的一个例子(每个标题为title1
的用户只有一个帖子)
new_post_title = 'title'
user_request = request.user
if new_post_title == 'title1':
post_exists = user_request.posts.filter(title='title1').exists()
if post_exists:
raise ValidationError(.....)
并且如果由于某种原因发生了引发完整性错误的竞争条件,则他们只会忽略此情况,并且服务器响应为A 500状态代码。我想我同意这一点,但是为什么不将验证放在模型的clean
方法中呢?。
当我以admin表单创建新对象时,这是模型中验证功能的堆栈跟踪。
- 调用模型的
full_clean
方法(此方法将调用接下来的三个函数)。 - 调用模型的
clean
方法。 - 调用模型的
clean_fields
。 - 调用模型的
validate_unique
。 - 调用模型的
save
方法。
我可以将验证放到干净的地方,并且不仅可以在表单中验证,而且.....窗体有一些技巧,因为默认情况下,如果我创建了save方法,则默认不会在save方法中调用clean,clean_fields和validate_unique。 shell中的post对象,唯一可以调用的函数是save
,所以...我可以在full_clean
方法中调用save
方法,此函数负责call clean,clean_fields和validate_unique(供表单使用),结果类似于:
def save(self,force_insert=False,force_update=False,using=None,update_fields=None):
self.full_clean()
return super().save(force_insert=force_insert,force_update=force_update,using=using,update_fields=update_fields)
一切似乎都是完美的,因为验证是在序列化程序,表单,shell中验证的,但是....表单在调用模型中的full_clean
之前先调用save
,然后在模型中调用{{ 1}}再次调用save
,这不是我遇到的唯一问题,当我使用full_clean
表达式并调用F
方法时,验证会引发TypeError,因为使用save
表达式的字段不是有效类型(它们不是整数或str,它们是F表达式)。
那么,什么是最佳解决方案?
更新了25/08/2020
我发现了将F
方法添加到full_clean
方法中的方法的其他方面。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)