【问题标题】:Django: avoid race condition for field which value based on aggregationDjango:避免基于聚合的字段的竞争条件
【发布时间】:2019-02-06 14:07:16
【问题描述】:

有示例模型:

class MyModel(models.Model):
    name = models.CharField()
    version = models.IntegerField()

我需要根据同名实例的最大版本设置version 字段值。为此,我重写 save 方法:

   def save(self, *args, **kwargs):
       max_version = MyModel.objects \
           .filter(name=self.name) \
           .aggregate(max_version=Max('version'))['max_version'] or 0
       self.version = max_version + 1
       super(MyModel, self).save(*args, **kwargs)

这里如何避免竞争条件?

编辑:版本必须是唯一的(在同名的实例之间),但顺序不太重要。

【问题讨论】:

    标签: django race-condition


    【解决方案1】:

    我认为一个简单的原子transaction 应该可以解决您的问题。

    from django.db import transaction
    
    
    def save(self, *args, **kwargs):
        with transaction.atomic():
            max_version = MyModel.objects \
               .filter(name=self.name) \
               .aggregate(max_version=Max('version'))['max_version'] or 0
            self.version = max_version + 1
            super(MyModel, self).save(*args, **kwargs)
    

    虽然超出了实际问题的范围,但您可能只想在创建记录时更新version 字段(第一次保存)。您可以通过验证 pkNone 来做到这一点。

    from django.db import transaction
    
    
    def save(self, *args, **kwargs):
        if self.pk is None:
            with transaction.atomic():
                max_version = MyModel.objects \
                   .filter(name=self.name) \
                   .aggregate(max_version=Max('version'))['max_version'] or 0
                self.version = max_version + 1
                super(MyModel, self).save(*args, **kwargs)
    
        else:
            super(MyModel, self).save(*args, **kwargs)
    

    【讨论】:

      猜你喜欢
      • 2014-04-02
      • 1970-01-01
      • 2015-01-30
      • 2010-09-25
      • 1970-01-01
      • 1970-01-01
      • 2015-04-29
      • 2010-09-25
      • 2019-06-12
      相关资源
      最近更新 更多