1

所以我有两个模型:

class Unit(models.Model):
   name = models.CharField()

class Session(models.Model):
   unit = models.ForeignKey(Unit)
   startDateTime = models.DateTimeField()
   endDateTime = models.DateTimeField() 

用户可以为在用户请求的日期/时间开始和结束的会话预订“单元”。不能同时使用任何单元,我想通过确保每个单元不能预订重叠会话来强制执行这一点。如果可能的话,我想用一个底层查询来做到这一点,这大概保证了更新的原子性?

我提出了两种方法,但我都不满意:

执行这个原始 SQL:

insert into "myapp_session" user_id, unit_id, startDateTime, endDateTime 
select 6, 2, '2013-05-18 02:09:02', '2013-05-18 03:09:02' from "myapp_session" 
where not exists 
(select * from "myapp_session" where unit_id=2 AND ("startDateTime" BETWEEN '2013-05-18 02:09:02' AND '2013-05-18 03:09:02' OR "endDateTime" BETWEEN '2013-05-18 02:09:02' AND '2013-05-18 03:09:02'));

这应该只在没有与它重叠的预订时插入一个新的会话。是否有可能让 ORM 做类似的事情?

另一种方法是select_for_update()在 Unit 上使用,有效地将其用作锁。

unitLock = list(Unit.select_for_update().filter(id=2)) # list() forces evaluation, this should block others until we have finished inserting the session?
overlappingSessions = Session.objects.filter(startDateTime__range=[requestedStart, requestedEnd], endDateTime__range=[requestedStart, requestedEnd])
if not overlappingSessions.exists():
    Session.objects.create(unit=2, startDateTime=requestedStart, endDateTime=requestedEnd)
# the lock should be freed as soon as the view function returns

这只会锁定 Units 表中的一行,因此仍然可以同时添加其他 Units 的其他会话。

另一种相关方法可能是将“sessionInsertInProgress”字段添加到 Unit。假设这将自动更新,它将阻止其他并发进程继续在单元上插入会话,同时允许为其他单元预订会话不受阻碍。

4

0 回答 0