在django模型字段

时间:2015-04-22 17:15:03

标签: python django orm django-orm

我在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对象还是别的什么?

2 个答案:

答案 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