sie*_*iej 4 python mysql django postgresql validation
我有一个简单的模型:
class InvitationRequest(models.Model):
email = models.EmailField(max_length=255, unique=True)
Run Code Online (Sandbox Code Playgroud)
一个简单的模型形式:
class InvitationRequestForm(forms.ModelForm):
class Meta:
model = InvitationRequest
Run Code Online (Sandbox Code Playgroud)
现在,假设我尝试以标准方式处理它:
form = InvitationRequestForm(request.POST)
if form.is_valid():
form.save()
Run Code Online (Sandbox Code Playgroud)
存在竞争条件,因为验证执行简单SELECT查询以确定是否已经存储了这样的电子邮件,并且如果一切正常,则它继续进行form.save().如果有一个并发进程在同一时刻执行相同操作,则两个表单都将验证,并且两个进程都将调用,form.save()因此一个将成功,另一个将失败导致IntegrityError.
处理这个问题的标准方法是什么?
我希望在表单对象中有一个标准错误,因此我可以将其传递给模板并通知用户该问题.
我知道:
SERIALIZABLE事务包装所有东西(在MySQL中,因为它执行下一个键锁定每次选择)Model._perform_unique_checks并使其使用select_for_update(由于下一个键锁定,与MySQL一起使用)这些解决方案都没有吸引力,我也使用PostgreSQL,它与MySQL在这个领域不同.
标准方法是不处理这个,如:
如果出于某种原因,你必须确定问题不会发生,那么你就是靠自己.
我没有详细分析事件的顺序,但我认为使用SERIALIZABLE隔离级别不会真正有用,它只会导致IntegrityError(或DatabaseError)在不同的地方引发.
Model._perform_unique_checks如果可能的话,向我推翻声音就像一个坏主意一样,你最好远离猴子补丁(这里有可能).
至于使用表锁来防止不可能出现的错误......好吧,我不是一个大粉丝所以我也不能推荐.
这是一个类似问题的一个很好的答案:https://stackoverflow.com/a/3523439/176186 - 我同意捕获IntegrityError和重试可能是处理问题最简单明智的方法.
编辑:我发现这个:Symfony2 - 如何在表单提交后从唯一约束错误中恢复?我同意@pid的回答.
我同意 Tomasz Zielinski 的观点,通常的做法是不要担心这一点。对于大多数用例来说,这是不值得的。
如果它很重要,最好的方法可能是乐观并发。在这种情况下,它可能看起来像(未经测试):
from django.forms.util import ErrorList
def handle_form(request)
form = InvitationRequestForm(request.POST)
try:
if form.is_valid():
form.save()
return HttpResponseRedirect(...) # redirect to success url
except IntegrityError:
form._errors['email'] = ErrorList()
form._errors['email'].append('Error msg')
return render(...) # re-render the form with errors
Run Code Online (Sandbox Code Playgroud)
SERIALIZABLE在这里并没有真正的帮助。正如PostgreSQL 文档所明确的那样,您必须准备好处理序列化失败,这意味着代码看起来与上面几乎相同。(不过,如果您没有强制数据库抛出异常的约束,这会有所帮助。)unique
| 归档时间: |
|
| 查看次数: |
1617 次 |
| 最近记录: |