首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Django模型实现时间表(调度)功能的体系结构

Django模型实现时间表(调度)功能的体系结构
EN

Stack Overflow用户
提问于 2015-11-13 20:42:29
回答 1查看 2K关注 0票数 6

我正在开发Django应用程序,目的是为10K+人员(以及将来更多的人)维护时间表(时间表)。基本上,问题陈述如下:每个人都有各自的时间表,明年有空位。它是离散的,步骤为15分钟。我需要开发模型体系结构(这将意味着下面的数据库设计)来完成以下工作:

  1. 查询给定人员的所有空闲时隙。
  2. 询问所有在某一时间有空的人。

例如,我有约翰,他从11月14日上午8点到下午14点自由,萨拉从上午10点到11月14日上午11点自由。如果我质疑约翰的空闲时间,我想得到“上午8:00-下午14 :00-11月14日”。如果我质疑“早上8点到11点免费的人”,我就会得到约翰,因为萨拉直到上午10点才有空。如果我质疑“从上午10点到上午11点自由的人”,我想得到约翰和萨拉。我考虑过这个问题,我的想法如下。

解决方案№1:我们创建了一个模型FreeTimeSlot,它可以存储每15分钟时间间隔的信息,并从人的角度构建与其相关的信息。

代码语言:javascript
复制
    class Person(models.Model):
        name = models.CharField(max_length=32, null=False, blank=False)
        free_slots = models.ManyToManyField(FreeTimeSlot, related_name='tutor_set', null=True, blank=True, through='PersonSlot')

    class TimeSlot(models.Model):
        time = models.DateTimeField(db_index=True) #perhaps other field type

    class PersonSlot(models.Model):
        person = models.ForeignKey(Person)
        timeslot = models.ForeignKey(Slot)

        class Meta:
            db_table = 'person_free_slots'
            unique_together = (('timeslot', 'person'))

在接下来的一年中,我们每隔15分钟就创建365*24*4 TimeSlot模型,如果person在他的计划中指定了空闲时间,我们就添加到该TimeSlot中。使用这种架构,为人获得免费的时隙就像通过管理器一样简单: person.free_time_slots使所有的人在特定的时间(例如10-10:45)自由也很容易,平滑就像:

代码语言:javascript
复制
timeslots = TimeSlot.objects.filter(time__in=['10:00', '10:15', '10:30'])
PersonSlot.objects.filter(timeslot__in=timeslots).values('person')

解决方案2:我们避免为每个时隙创建模型,但将日期保存在PersonTime模型本身中:

代码语言:javascript
复制
    class Person(models.Model):
        name = models.CharField(max_length=32, null=False, blank=False)

    class TimeSlot(models.Model):
        person = models.ForeignKey(Person, related_name='slots')
        time_start = models.DateTimeField(db_index=True)
        time_end = models.DateTimeField(db_index=True)

获取空闲时隙列表也很容易(person.slots)。在某一时间(例如10-10:45)让所有人自由,就像:

代码语言:javascript
复制
TimeSlot.objects.filter(time_start__gte="10:00", time_end__lte="10:45").values('person')

此解决方案不适用于相交的间隔,我也不确定查询索引间隔时间(在同一字段上使用gte和lte比较)是否有效,并将快速工作。如果有关系我就用Postgres。我还用伪代码编写了时间查询,以使代码更简单。

因此,我的问题是,django开发人员如何才能更好地实现这个功能,从而为大数据上的两个查询提供速度?我希望能就我目前的解决方案或新想法的可能的注意事项/好处提出建议。

EN

回答 1

Stack Overflow用户

发布于 2015-11-18 08:44:49

让我们把这个问题分成两部分。

第1部分-数据编码

考虑编码与时隙相关的数据。如果您需要精确的15分钟,您有96个插槽(4个插槽在1小时*24小时在一天中),持续时间为15分钟在任何给定的一天。每个插槽可以有两种可能的状态:1-插槽是空闲的,0-插槽是繁忙的(或者反之亦然,如果你愿意的话)。因此,您可以用0s和1s的字符串来表示每天的时间表。例如,字符串(仅为便于阅读而添加的空格) 0000 0000 0000 0000 0000 0000 0000 0000 0000 1110 0000 ...表示上午00:00AM至09:00AM (没有人在夜间工作)之间的繁忙时隙,然后是上午9:00到9:45之间的空闲时间(连续三个1),然后是从9:45AM开始的繁忙时间时段。

所以,你可以这样写你的模型:

代码语言:javascript
复制
class Person(models.Model):
    name = models.CharField(max_length=32)

class DailySchedule(models.Model):
    person = models.ForeignKey(Person, related_name='day_schedule')
    date = models.DateField()
    schedule = models.CharField(max_length=96)

第2部分-查询

因此,我们对有关可用/繁忙时隙的信息进行了编码,但是如何从数据库中提取它呢?幸运的是,Django有regex字段查找的可能性!幸运的是,Django 1.4支持它!

因此,为了在特定的时间段内找到谁可用,可以使用DailySchedule.objects.filter(date=date, schedule__regex=r'<expression>')。由于提取不同时间框架的表达式并不明显,我们需要一个支持函数:

代码语言:javascript
复制
def time_slot_to_regex(start_time, end_time):
    # times should be in HH:MM format
    start_hour, start_minutes = start_time.split(':')
    end_hour, end_minutes = end_time.split(':')

    slots_before_needed_time = (int(start_hour)*4 + int(start_minutes)/15)

    # compute how many hours are between given times and find out nr of slots
    hour_duration_slots = (int(end_hour) - int(start_hour)) * 4  # 4 slots in each hour

    # adjust nr of slots according to minutes in provided times. 
    # e.g. 9:30 to 10:45 - we have 10-9=1 hour, which is 4 time slots, 
    # but we need to subtract 2 time slots, because we don't have 9:00 to 10:00, 
    # but 9:30 to 10:00 so we subtract 30/15=2 timeslots and add what is left 
    # from the incomplete hour of 10:45 time, which is 45/15 minutes = 3 slots
    minute_duration_slots = int(end_minutes)/15 - int(start_minutes)/15

    total_duration = hour_duration_slots + minute_duration_slots

    regular_expression = r'^[01]{%d}1{%d}' % (slots_before_needed_time, total_duration)

    return regular_expression

让我们弄清楚这个函数是如何工作的,

假设我们想找出上午9:15到9:45之间有谁可用我们称之为slots_expression = time_slot_to_regex('9:15', '9:45'),它计算:

  • slots_before_needed_time = 37,它是通过将9乘以4+ 15/15得到的。这是我们不关心的插槽数,它将进入我们的regular_expression字符串- '^[01]{37}'的第一部分。
  • hour_duration_slots = 0,因为两个时间值中的小时是相同的。
  • minute_duration_slots = 2,我们从45/15中减去15/15
  • 前面的2加在一起使我们需要在regular_expression中设置为1的两个插槽,从而获得'^[01]{37}1{2}'

现在我们可以将这个正则表达式提供给我们的过滤器,获得DailySchedule.objects.filter(schedule__regex=slots_expression)和瞧!,我们得到了结果。

保存数据过程

我已经描述了编码数据的原理,但是没有提到编码它的过程。通过使用另一个支持函数可以轻松地完成这一任务,该函数接受一串现有的繁忙/可用插槽以及更新现有计划的start_dateend_date。如果你也需要这个方法,请告诉我。

优点

  • 没有M2M关系,这会导致更快的查询
  • 可以使用不同的正则表达式在一天内搜索几个空闲时段(例如,^[01]{36}1{4}[01]{24}1{4}将查找从上午9点到上午10点从下午4点到下午5点可用的人。
  • 相对简单的实现
  • 作为一个副作用,您可以更容易地访问来查找繁忙的时间段,因为您将在数据库中获得所需的信息,并且不需要为其运行计算。

缺点

  • 不是冗长的,对某些人来说,这可能是令人困惑的
  • 在数据库中需要更多的空间,因为您将节省空闲和繁忙的时间插槽。
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33701418

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档