爲避免競爭條件,最好讓數據庫處理表的完整性,這是數據庫的一個要求。
爲此,請捕獲通過保存模型實例引發的任何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