我在django模型中实现了一个字段,该字段调用以下函数作为默认值
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:
default_value_field = CharField(default=get_default_value)
虽然我可能错了,但我担心这种实施可能会导致竞争状况。
有更好的方法吗?可以使用F对象还是别的什么?
答案 0 :(得分:1)
为避免竞争条件,最好让数据库处理表的完整性,这是数据库的一部分。
要执行此操作,请通过保存模型实例来捕获任何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)
答案 1 :(得分:0)
似乎django对于queryset API有select_for_update
。这可能是解决我的问题的方法。
https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-for-update