【问题标题】:Better way to set default value in django model field在 django 模型字段中设置默认值的更好方法
【发布时间】:2015-06-30 12:37:12
【问题描述】:

我正在 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 对象还是其他东西?

【问题讨论】:

    标签: python django orm django-orm


    【解决方案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)
    

    【讨论】:

    • 我目前正在查看select_for_update,看看是否会成功。我想这也是一种有效的替代方法,所以接受它。循环内save 之后不会有break 吗?
    • @sagarchalise 我不知道select_for_update,但它似乎正是您正在寻找的,如果您设法使用它来解决您的问题,您应该发布答案并接受它。
    【解决方案2】:

    似乎 django 有 select_for_update 用于查询集 API。这可能是我的问题的解决方案。

    https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-for-update

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多