型号:
class CouponUsage(models.Model):
coupon = models.ForeignKey('Coupon', on_delete=models.CASCADE, related_name="usage")
date = models.DateTimeField(auto_now_add=True)
class Coupon(models.Model):
name = models.CharField(max_length=255)
capacity = models.IntegerField()
@property
def remaining(self):
usage = self.usage.all().count()
return self.capacity - usage
观看次数:
def use_coupon(request):
coupon = Coupon.objects.get(condition)
if coupon.remaining > 0:
# do something
我不知道如何处理上面代码中的并发问题,我相信一个可能的错误是,当视图中的if子句正在执行时,可以创建另一个CouponUsage对象。 我该如何处理呢?
当在视图的if子句中时,如何防止创建CouponUsage对象
答案 0 :(得分:0)
执行此操作的一种方法是依赖数据库完整性检查和事务。假设您的容量必须始终在[0,+ infinity]范围内,则可以将Coupon
模型更改为使用PositiveIntegerField
而不是IntegerField
:
class Coupon(models.Model):
name = models.CharField(max_length=255)
capacity = models.PositiveIntegerField()
然后,您需要在每次创建Coupon
时更新CouponUsage
的容量。您可以覆盖save()
方法以反映此更改:
from django.db import models, transaction
class CouponUsage(models.Model):
coupon = models.ForeignKey('Coupon', on_delete=models.CASCADE, related_name="usage")
date = models.DateTimeField(auto_now_add=True)
@transaction.atomic()
def save(self, ...): # Arguments missing
if not self.pk: # This is an insert, you may want to raise an error otherwise
self.coupon.capacity = models.F('capacity') - 1 # The magic is here, this is executed at the database level so no problem with old in memory values
self.coupon.save()
super().save(...)
现在,无论何时创建CuponUsage
,您都将更新关联的Coupon
实例的容量。这里的关键是,不是从数据库中将值读取到python的内存中,而是先进行更新然后保存,否则可能导致结果不一致,而是使用an F expression在数据库级别对capacity
进行更新。这样可以保证没有两个事务使用相同的值。
现在,请注意,通过使用PositiveInteger
字段而不是IntegerField
,数据库还将保证capacity
不能低于0。因此,如果您现在尝试创建{{ 1}}实例,使得CuponUsage
容量将为负值,则会出现异常,从而阻止创建此类Cupon
。
您现在需要通过执行以下操作来在代码中利用此优势:
CuponUsage
如果在获取优惠券时您需要做可能会失败的事情,并且在这种情况下需要“还原”使用情况,则可以将整个def use_coupon(request):
coupon = Coupon.objects.get(condition)
try:
usage = CuponUsage.objects.create(coupon=coupon)
# Do whatever you want here, you already 'consumed' a coupon
except IntegrityError: # Check for the specific exception
# Sorry no capacity left
pass
函数包含在交易中。 / p>