为避免竞争条件,最好让数据库处理表的完整性,这是数据库的一个要求。
为此,请捕获通过保存模型实例引发的任何IntegrityError
,并在失败时再次尝试使用不同的值。
from django.db import IntegrityError, models, transaction
def get_default_value():
a = MyModel.objects.aggregate(max_id=Max('id'))
return get_unique_value_based_on_num(a['max_id'] or 0)
class MyModel(models.Model):
# Have unicity enforced at database level with unique=True.
default_value_field = models.CharField(max_length=200, unique=True)
def save(self):
if not self.default_value_field:
max_tries = 100 # Choose a sensible value!
for i in range(max_tries):
try:
self.default_value_field = get_default_value()
# Atomic block to rollback transaction in case of IntegrityError.
with transaction.atomic():
super(MyModel, self).save()
break
except IntegrityError:
# default_value_field is not unique, try again with a new value.
continue
else:
# Max tries reached, raise.
raise IntegrityError('Could not save model because etc...')
else:
super(MyModel, self).save(*args, **kwargs)
我目前检查出'select_for_update',看看是否会工作了。我想这也是一个有效的替代方法,因此接受它。循环内的'save'后面不会有'break'吗? – sagarchalise
@sagarchalise你是绝对正确的。 – aumo
@sagarchalise我不知道'select_for_update',但它似乎正是你要找的,如果你设法用它来解决你的问题,你应该发布一个答案并接受它。 – aumo