Django预约系统如何展示未预约日期对应11:00-21:00的可预约时段
结论
现有实现可直接扩展完成需求,无需重构原有逻辑。
实现步骤
- 第一步:保留原有计算未预约日期的逻辑,得到未来5天内无任何预约的日期列表
- 第二步:自定义时段粒度(默认按1小时为例,可按需调整为30/45分钟等),为每个未预约日期生成11:00-21:00的所有候选时段
- 第三步:过滤掉和已有预约时段重叠的候选时段,剩余即为可预约时段
完整实现代码
from datetime import date, timedelta, datetime, time from django.utils import timezone # 配置项:可根据业务调整 NUM_DAYS = 5 SLOT_DURATION = timedelta(hours=1) # 时段粒度 BUSINESS_START = 11 # 营业开始时间(小时) BUSINESS_END = 21 # 营业结束时间(小时) # 原有逻辑:计算未预约日期 start_date = date.today() timeframe = [start_date + timedelta(days=d) for d in range(NUM_DAYS)] fully_booked_dates = set(Appointment.objects.values_list("start_appointment__date", flat=True).distinct()) available_dates = set(timeframe) - fully_booked_dates # 新增逻辑:为每个可用日期计算可预约时段 available_slots = {} for d in available_dates: # 生成当日所有候选时段 current = timezone.make_aware(datetime.combine(d, time(BUSINESS_START, 0))) business_end = timezone.make_aware(datetime.combine(d, time(BUSINESS_END, 0))) candidate_slots = [] while current < business_end: slot_end = current + SLOT_DURATION candidate_slots.append( (current, slot_end) ) current = slot_end # 查询当日所有已预约时间段 existing_appts = Appointment.objects.filter( start_appointment__date=d ).values_list("start_appointment", "end_appointment") # 过滤冲突时段 valid_slots = [] for slot_start, slot_end in candidate_slots: is_conflict = False for appt_start, appt_end in existing_appts: # 时段重叠判断逻辑:两个时间段有交集即为冲突 if not (slot_end <= appt_start or slot_start >= appt_end): is_conflict = True break if not is_conflict: valid_slots.append(slot_start) # 可按需返回时段起止或仅开始时间 available_slots[d] = valid_slots
优化建议
- 数据量较大时可一次性查询出所有
available_dates范围内的预约,避免循环查询数据库降低性能 - 若业务允许同一时段多人预约,可新增座位库存判断逻辑,无需直接排除整个时段
- 部署多区域服务时注意统一时区处理,所有datetime对象均使用Django的
timezone工具生成,避免时区不一致导致的时段判断错误
内容的提问来源于stack exchange,提问作者paniklas
相关产品推荐
相关产品推荐

