首页 > 解决方案 > Django 存储实际可用性并查询新预订的可用时间表

问题描述

在应用程序中,有两种类型的用户: StudentMentor

  1. 作为mentor用户类型,我可以设置基于每周的可用性
  2. 作为student用户类型,我可以看到mentor可用性。

===============================

所以我根据工作日WeekDayAvailableHour模型存储用户可用性

DAYS_OF_WEEK = (
    (0, 'Monday'),
    (1, 'Tuesday'),
    (2, 'Wednesday'),
    (3, 'Thursday'),
    (4, 'Friday'),
    (5, 'Saturday'),
    (6, 'Sunday'),
)
        
class WeekDay(models.Model):
    mentor = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="weekday"
    )
    weekday = models.IntegerField(choices=DAYS_OF_WEEK)
    

class AvailableHour(models.Model): #Based on weekday
    weekday = models.ForeignKey(
        WeekDay,
        on_delete=models.CASCADE,
        related_name="available_hour"
    )
    from_hour = models.TimeField()
    to_hour = models.TimeField()
  1. 作为用户类型student,我只能在mentor可用时间预订会话。

因此,当学生预订课程时,我们会将信息存储在模型下方。

 class BookingSession(models.Model):
   student = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="student_booking"
    )
    mentor = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="mentor_booking"
    )
    date = models.DateField()
    
    from_hour = models.TimeField()
    to_hour = models.TimeField()

那么现在有什么问题呢?

由于我们有用户AvailableHour,所以一旦学生预订了导师课程,那么指定的时间范围是无法获得导师资料的,对吧?以便其他学生可以看到导师的实际可用性。

所以你知道,如果我们从中获取查询集AvailableHour,并不意味着如果任何指定的时间范围已经预订并且预订的时间已经存储在BookingSession模型中,那么导师在那个时间可用

如果指定工作日AvailableHour中存在开始和结束时间,我想排除的记录BookingSession

我想向学生展示,导师的实际可用性是什么。

如果您知道它已经有预订,就像AvailableHour无法存储实际可用的一样!BookingSession

假设我在BookingSession表中有数据

booked_sesson = [
    {'date': '2021-08-02','from_hour': '12:30', 'to_hour': '12:15' }, # monday
    {'date': '2021-08-04','from_hour': '02:30', 'to_hour': '03:15' }, # Wednesday
]

和下面的WeekDay可用性AvailableHour表数据

available_based_on_weekday = [
    {
        "weekday": 1, 'opening_hour_time': [ # monday
            {'from_hour': '12:30', 'to_hour': '12:15'},
            {'from_hour': '12:30', 'to_hour': '12:15'},
            {'from_hour': '12:30', 'to_hour': '12:15'}
        ]
    },
    {
        "weekday": 7, 'opening_hour_time': [ # Saturday
            {'from_hour': '13:30', 'to_hour': '15:15'},
            {'from_hour': '15:30', 'to_hour': '16:15'},
            {'from_hour': '19:30', 'to_hour': '20:15'},
            {'from_hour': '23:30', 'to_hour': '23:45'}
        ]
    },
    {
        "weekday": 3, 'opening_hour_time': [ # Wednesday
            {'from_hour': '02:30', 'to_hour': '03:30'},
            {'from_hour': '17:30', 'to_hour': '18:15'},
            {'from_hour': '19:30', 'to_hour': '20:15'},
            {'from_hour': '21:30', 'to_hour': '22:30'}
        ]
    }
]

我期待什么输出结果? 查询后,我期待这些输出,并且应该逐月查询:

actual_availability = [
     {
         'date': '2021-08-01',
         'available': []
     },
     {
         'date': '2021-08-02',
         'available': [
            {'from_hour': '12:30', 'to_hour': '12:15'},
            {'from_hour': '12:30', 'to_hour': '12:15'}
         ]
     },
     {
         'date': '2021-08-03',
         'available': []
     },
     {
         'date': '2021-08-04',
         'available': [
            {'from_hour': '03:15', 'to_hour': '03:30'},
            {'from_hour': '17:30', 'to_hour': '18:15'},
            {'from_hour': '19:30', 'to_hour': '20:15'},
            {'from_hour': '21:30', 'to_hour': '22:30'}
         ]
     },
     {
         'date': '2021-08-05',
         'available': []
     },
     {
         'date': '2021-08-06',
         'available': []
     },
     {
         'date': '2021-08-07',
         'available': []
     },
     {
         'date': '2021-08-08',
         'available': []
     },
     {
         'date': '2021-08-09',
         'available': [
            {'from_hour': '12:30', 'to_hour': '12:15'},
            {'from_hour': '12:30', 'to_hour': '12:15'},
            {'from_hour': '12:30', 'to_hour': '12:15'}
         ]
     },
     # to be continued for a month by month
]

如果您有任何替代方法,我会欢迎,请在这里分享您的观点。

给你我试过的东西,它真的很愚蠢,不起作用。

real_available_date_slot = []
for obj in BookingSession.objects.filter(mentor_id='A mentor ID'):
    weekday =  obj.date.isoweekday()
    real_available = []

    available_hour = AvailableHour.objects.filter(weekday__weekday=weekday, weekday__mentor=obj.mentor)
    availables = available_hour.exclude(
        from_hour__gt=obj.to_hour
    ).exclude(
        to_hour__lt=obj.to_hour
    )
    
    for available in availables:
        real_available.append(
            {'from_hour': available.from_hour, 'to_hour': available.to_hour}
        )

    real_available_date_slot.append({
        obj.date: real_available
    })

我也尝试过不同的其他方式,但我无法提供任何解决方案

谁能分享您的想法,我们如何解决我的availability问题?您查询此类事情的方法是什么?或者我为这种情况做了不正确的数据库设计?

标签: pythondjangodjango-modelsdjango-querysetdjango-orm

解决方案


另一种方法,并以@Jimmar 的答案为基础,有一些变化:

Availability可以保存导师信息和导师的可用时间表。因此,导师可以有许多关于其可用性关系的项目,其中包括工作日信息以及时间段。

class Availability(models.Model):
    mentor = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="availability"
    )
    weekday = models.IntegerField(choices=DAYS_OF_WEEK)
    from_hour = models.TimeField()
    to_hour = models.TimeField()

例如,导师可以有这种可用性:

{'id': 1, 'mentor': 1, 'weekday': 1, 'from_hour': '12:15', 'to_hour': '12:45'}
{'id': 2, 'mentor': 1, 'weekday': 1, 'from_hour': '12:45', 'to_hour': '13:15'}
{'id': 3, 'mentor': 1, 'weekday': 1, 'from_hour': '13:15', 'to_hour': '14:45'}

反过来,Bookings现在可以保持studentand mentor_session( Availability) 关系,但与预定日期。这将支持获取Availability项目并按预订日期排除。

class BookingSession(models.Model):
    student = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="bookings"
    )
    mentor_session = models.ForeignKey(
        Availability,
        on_delete=models.CASCADE,
        related_name="bookings"
    )
    date = models.DateField()

例如,如果我们有以下预订:

{'id': 1, 'student': 1, 'mentor_session': 1, 'date': '2021-01-01'}
{'id': 2, 'student': 1, 'mentor_session': 1, 'date': '2021-01-02'}
{'id': 3, 'student': 1, 'mentor_session': 1, 'date': '2021-01-03'}

这意味着导师的可用性 id 1 由 id 1 的学生在上述日期预订。所以现在要根据日期获取导师的可用时间:

date = datetime.date(2021, 01, 01)
weekday = date.isoweekday()

Availability.objects.filter(mentor=mentor, weekday=weekday).annotate(
    is_booked_on_date=Exists(
        BookingSession.objects.filter(mentor_session=OuterRef('pk'), date=date)
    )
).filter(is_booked_on_date=False)

由于 ID 为 1 的可用性已在指定日期预订(它有一个预订会话),这应该只返回 date 的可用性 ID 2 和 3 2021-01-01

为了支持您想要的预期输出,您可以在特定日期范围内迭代每一天并使用上述查询的结果。


推荐阅读