在我的Django应用程序中,我具有以下两个模型:
class Event(models.Model):
capacity = models.PositiveSmallIntegerField()
def get_number_of_registered_tickets():
return EventRegistration.objects.filter(event__exact=self).aggregate(total=Coalesce(Sum('number_tickets'), 0))['total']
class EventRegistration(models.Model):
time = models.DateTimeField(auto_now_add=True)
event = models.ForeignKey(Event, on_delete=models.CASCADE)
number_tickets = models.PositiveSmallIntegerField(validators=[MinValueValidator(1)])
Run Code Online (Sandbox Code Playgroud)
get_number_of_registered_tickets()我需要在应用程序中的多个位置使用该方法(例如,模板渲染)。因此,我认为将其放入模型中也是有意义的,因为它与之相关,而且我经常听到拥有“胖模型和轻量级视图”是一件好事。
我现在的问题:为了防止两个人要为事件注册并联,我必须使用锁。范例:假设还有一张车票要注册。现在,向人们展示在我的网站上,同时单击“注册”。在不幸的情况下,这两个请求都可能是有效的,现在我的注册量超出了容量。
我是Django的新手,但阅读文档后,我认为这select_for_update()应该是解决方案,我在这里吗(我使用PostgreSQL,因此应该受到支持)?
但是,文档还说使用select_for_update()仅在交易中有效。
select_for_update()在支持SELECT ... FOR UPDATE该功能的后端使用自动提交模式评估查询集是TransactionManagementError错误的,因为在这种情况下行未锁定。如果允许,这将促进数据损坏,并且很容易由调用期望在一个事务之外的事务中运行的代码引起。
我现在的想法是更改模型方法get_number_of_registered_tickets()并添加select_for_update():
def get_number_of_registered_tickets():
return EventRegistration.objects.select_for_update().filter(event__exact=self).aggregate(total=Coalesce(Sum('number_tickets'), 0))['total']
Run Code Online (Sandbox Code Playgroud)
现在不同的问题:
select_for_update()正确的解决方案来解决我的问题吗?get_number_of_registered_tickets()鉴于它似乎只能在事务中使用,是否意味着我现在不能在不同的视图/模板中使用该方法?我是否必须在这里违反DRY并将带有select_for_update()的查询复制并粘贴到代码中的其他位置?TransactionManagementError在自动提交模式下(不使用任何事务)不会提高使用时间。是什么原因,或者我误会了什么?在查询集select_for_update()上做EventRegistration不是要走的路。这会锁定指定的行,但大概您试图防止的冲突涉及创建新的 EventRegistrations. 你的锁不会阻止。
相反,您可以获取Event. 就像是:
class Event(models.Model):
...
@transaction.atomic
def reserve_tickets(self, number_tickets):
list(Event.objects.filter(id=self.id).select_for_update()) # force evaluation
if self.get_number_of_registered_tickets() + number_tickets <= self.capacity:
# create EventRegistration
else:
# handle error
Run Code Online (Sandbox Code Playgroud)
请注意,这使用transaction.atomic装饰器来确保您在事务中运行。
| 归档时间: |
|
| 查看次数: |
1628 次 |
| 最近记录: |