我的设置类似于以下内容:
class TimeFrame(models.Model):
"""A range of dates and times. On each date in the given range,
associated objects are available only within the provided time
range.
"""
class Meta:
index_together=(('time_from','time_until'),)
date_from = models.DateField(db_index=True)
date_until = models.DateField(db_index=True)
time_from = models.TimeField(db_index=True)
time_until = models.TimeField(db_index=True)
scheduled_model = models.ForeignKey(ScheduledModel)
time_until
可能会小于time_from
,这会使情况严重复杂化。例如,某些东西可能在晚上9点到凌晨2点之间提供。我已经编写了一个过滤器来查找可用的TimeFrame
,如下所示:
open_time_frame_filter = (
Q(
# Cases like 9pm-2am.
Q(time_from__gt=F('time_until')),
Q(
# Past 9pm.
time_from__lte=time,
date_from__lte=date,
date_until__gte=date
) | Q(
# Before 2am.
time_until__gte=time,
date_from__lte=date - datetime.timedelta(days=1),
date_until__gte=date - datetime.timedelta(days=1)
)
) | Q(
# Normal cases.
Q(time_from__lte=F('time_until')),
Q(time_from__lte=time),
Q(time_until__gte=time),
Q(date_from__lte=date),
Q(date_until__gte=date)
)
)
可以预见, time
和date
是时间和日期。不幸的是,这里的某些东西是非常低效的,并且最终效率低于仅仅检索适合并在python中迭代它们的所有TimeFrame
。在使用古老的跟踪方法(评论出来)来发现根本原因之后,它似乎是F
个对象的行,其中一个字段与另一个字段进行比较,这会减慢查询速度。我需要能够在这里使用过滤器以获得灵活性,但是由于当前的低效率,它太慢了。为了与项目的其余部分保持一致,我希望远离原始SQL。但是,我不确定从哪里开始解决这类问题。
修改
TimeFrame
个对象在时间范围内通过外键绑定到一个单独的对象(多对一)。然后更精确地描述过滤器:
class ScheduledModel(models.Model):
"""A model with an associated schedule (described by several time
frames).
"""
@property
def is_open(self):
"""Is the model currently open?"""
time = datetime.now().time()
date = datetime.now().date()
return TimeFrame.objects.filter(
Q(scheduled_model_id=self.id),
open_time_frame_filter # As defined above.
).exists()
在手动python版本中,首先通过id检索时间帧的查询集,然后迭代以确定是否有任何打开。原则上,这个查询应该做同样的事情,并且会更快,因为time_from,time_until,date_from和date_until被索引,time_from和time_until被索引在一起。每个预定模型只有大约十个时间帧,但总共有数十万个时间帧。
编辑2
我已经纠正了原始模型,以明确已经尝试过的内容。