django - 确保创建了一个相关对象,竞争条件

django - make sure one related object is created, race condition

我有一个带外键的 table。 (我这里特意用外键而不是一对一)
我有一个订单模型:

class Order:
  name = models.CharField(max_length=50)
  user = models.ForeignKey(User)
  active = models.BooleanField(default=True)
  # more fields..

而且我希望每个用户只有一个此模型的实例。

我有一个保存它的简单表单(和视图)。我有这个代码:

try:
   instance = Order.objects.get(user=user)
except Order.DoesNotExist:
   instance = None
form = OrderForm(instance=instance)

但我注意到如果客户端同时触发两个后续请求(注意到我使用 ajax),那么可能会创建两个实例,尽管我进行了以下验证(假设更新现有的)。

这非常重要,因为我的其他代码期望每个用户只有一个此模型的实例。我怎样才能在 Django 中执行它?我根据自己的观点尝试了以下方法:

@method_decorator(transaction.atomic, name='dispatch')

但是没用。 正如我所说,我不能在这里使用一对一字段。

您可以为用户设置unique=true。这将确保每个用户只能下一个订单。

class Order:
  name = models.CharField(max_length=50)
  user = models.ForeignKey(User, unique=true)
  active = models.BooleanField(default=True)

您可以使用 unique_together 和可为空的字段在数据库级别强制执行唯一性:

class Order:
    name = models.CharField(max_length=50)
    user = models.ForeignKey(User)
    active = models.NullBooleanField(default=True)

    class Meta:
        unique_together = (('user', 'active'), )

诀窍是将 active 设置为 None 而不是 False 用于非活动订单。由于 NULL 值在数据库级别不被视为相等,因此用户可能有多个非活动订单,但只有一个活动订单。