You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于科目、年级及多预约日期筛选可用家教?

解决基于科目、年级及多日期筛选未被预约家教的问题

问题背景

业务需求为:家长按科目、年级及多个预约日期搜索家教,需展示对应条件下未被预约的所有家教。现有Django模型及ViewSet代码存在逻辑缺陷,无法满足需求。

现有模型代码

TutorProfile 模型

class TutorProfile(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    which_grade = models.ForeignKey(
        Grade, on_delete=models.CASCADE, blank=True, null=True)
    tutoring_subject = models.ForeignKey(
        TutoringSubject, on_delete=models.CASCADE, blank=True, null=True)

    sat = models.BooleanField(default=False)
    sat_time = models.CharField(
        _("Saturday Time:"), max_length=255, null=True, blank=True)
    sun = models.BooleanField(default=False)
    sun_time = models.CharField(
        _("Sunday Time:"), max_length=255, null=True, blank=True)
    mon = models.BooleanField(default=False)
    mon_time = models.CharField(
        _("Monday Time:"), max_length=255, null=True, blank=True)
    tue = models.BooleanField(default=False)
    tue_time = models.CharField(
        _("Tuesday Time:"), max_length=255, null=True, blank=True)
    wed = models.BooleanField(default=False)
    wed_time = models.CharField(
        _("Wednesday Time:"), max_length=255, null=True, blank=True)
    thu = models.BooleanField(default=False)
    thu_time = models.CharField(
        _("Thursday Time:"), max_length=255, null=True, blank=True)
    fri = models.BooleanField(default=False)
    fri_time = models.CharField(
        _("Friday Time:"), max_length=255, null=True, blank=True)

Booking 模型

class Booking(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    book_day = models.CharField(
        _("Book Day"), max_length=255, null=True, blank=True)
    book_time = models.CharField(
        _("Book Time"), max_length=255, null=True, blank=True)    
    status = models.CharField(
        _("Status"), max_length=255, null=True, blank=True)

现有代码核心问题

  1. Booking模型缺失关键关联:未关联TutorProfile,无法记录具体是哪个家教被预约,导致无法筛选未被预约的家教。
  2. 多日期处理失效:循环中第一次满足条件就直接return,仅处理第一个日期,忽略后续日期。
  3. 参数未利用:科目、年级参数未加入筛选逻辑,完全无效。
  4. 字段匹配错误:周五筛选错误使用thu=1,应为fri=1。
  5. 未排除已预约家教:仅判断日期是否有预约,未关联到具体家教,无法排除已被预约的对象。

修复方案与代码实现

第一步:修正Booking模型

添加tutor_profile外键,关联家教与预约记录:

class Booking(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    # 新增:关联对应的家教
    tutor_profile = models.ForeignKey(TutorProfile, on_delete=models.CASCADE, related_name='bookings')
    book_day = models.CharField(_("Book Day"), max_length=255, null=True, blank=True)
    book_time = models.CharField(_("Book Time"), max_length=255, null=True, blank=True)    
    status = models.CharField(_("Status"), max_length=255, null=True, blank=True)

第二步:重写get_queryset方法

实现完整的筛选逻辑:

from datetime import datetime
from django.db.models import Q

def get_queryset(self):
    subject_param = self.request.GET.get('subject')
    bookday_str = self.request.GET.get('book_day')
    grade_param = self.request.GET.get('grade')

    # 初始化基础查询集
    queryset = TutorProfile.objects.all()

    # 筛选指定科目
    if subject_param:
        queryset = queryset.filter(tutoring_subject_id=subject_param)
    
    # 筛选指定年级
    if grade_param:
        queryset = queryset.filter(which_grade_id=grade_param)
    
    # 处理多日期筛选与排除已预约家教
    if bookday_str:
        book_days = [day.strip() for day in bookday_str.split(",")]
        # 日期名称与模型字段映射
        day_field_map = {
            "Monday": "mon",
            "Tuesday": "tue",
            "Wednesday": "wed",
            "Thursday": "thu",
            "Friday": "fri",
            "Saturday": "sat",
            "Sunday": "sun"
        }

        # 筛选所有指定日期都有空的家教(若需求为任意日期有空,可改为OR条件)
        for day_str in book_days:
            try:
                day_name = datetime.strptime(day_str, "%d-%m-%Y").strftime("%A")
                field_name = day_field_map.get(day_name)
                if field_name:
                    queryset = queryset.filter(**{field_name: True})
            except ValueError:
                # 跳过格式错误的日期
                continue
        
        # 排除在指定日期已被预约的家教(可根据需求添加status过滤,如status="confirmed")
        booked_tutor_ids = Booking.objects.filter(
            book_day__in=book_days
        ).values_list('tutor_profile_id', flat=True)
        
        queryset = queryset.exclude(id__in=booked_tutor_ids)
    
    return queryset

关键逻辑说明

  1. 关联预约与家教:通过Booking.tutor_profile建立关联,才能精准定位已被预约的家教。
  2. 多日期筛选:遍历所有指定日期,确保家教在每个日期都有可用时间(若需求为"任意日期有空",可将循环中的filter改为Q对象的OR组合)。
  3. 排除已预约:通过values_list获取所有已被预约的家教ID,用exclude从查询集中移除。
  4. 异常处理:捕获日期格式错误,避免单个无效日期导致整个查询失败。
  5. 参数复用:充分利用科目、年级参数,实现精准筛选。

内容的提问来源于stack exchange,提问作者Iqbal Hussain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 00:50:16