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

如何在Django表单校验中通过ValidationError返回可用预约时段列表

实现方案

只需要修改forms.py中BookingForm的clean校验方法即可,具体修改逻辑如下:

  1. 先获取用户提交的配送日期、配送时间,若两个字段未通过基础校验(比如用户未填写)则直接返回校验结果
  2. 查询该配送日期下所有已预约记录的时段小时数
  3. 用全量可选时段(7-12点)减去已预约时段,得到可用时段列表并格式化
  4. 若用户选择的时段已被占用,将可用时段拼入错误提示抛出即可

修改后的完整BookingForm代码如下:

from django import forms
from bookmyslot.models import Booking,Customer
from bootstrap_datepicker_plus import DatePickerInput
import datetime as dt
from django.utils import timezone


HOUR_CHOICES = [(dt.time(hour=x), '{:02d}:00'.format(x)) for x in range(7, 13)]

class BookingForm(forms.ModelForm):

    def __init__(self,*args,**kwargs):
        user = kwargs.pop('username',None)
        super(BookingForm,self).__init__(*args,**kwargs)
        self.fields['qty_plts'].label = "Quantity Of Pallets"
        self.fields['cbm'].label = "Shipment CBM"
        self.fields['delivery_date'].label = "Delivery Date"
        self.fields['delivery_time'].label = "Delivery Time"
        self.fields['customer_name'].label = "Customer Name"
        self.fields['customer_name'].queryset = Customer.objects.filter(username=user)

    def clean(self):
        cleaned_data = super(BookingForm,self).clean()
        delivery_date = cleaned_data.get('delivery_date')
        delivery_time = cleaned_data.get('delivery_time')
        # 字段未通过基础校验直接返回
        if not delivery_date or not delivery_time:
            return cleaned_data
        
        # 查询当前日期已预约的小时列表
        booked_hours = Booking.objects.filter(
            delivery_date=delivery_date
        ).values_list('delivery_time__hour', flat=True)
        # 计算可用时段
        free_hours = sorted(set(range(7,13)) - set(booked_hours))
        # 可选优化:判断当日是否还有可用时段
        if not free_hours:
            raise forms.ValidationError("该日期所有时段均已约满,请选择其他日期")
        free_slot_str = "、".join([f"{h:02d}:00" for h in free_hours])

        # 校验当前时段是否已被占用
        if delivery_time.hour in booked_hours:
            raise forms.ValidationError(f"请求时段已被预约,请从以下可用时段中选择:{free_slot_str}")

        return cleaned_data

    class Meta:
        model = Booking
        fields = ('customer_name','qty_plts','cbm','delivery_date','delivery_time')
        widgets = {'delivery_date':DatePickerInput(options={"daysOfWeekDisabled":[0,6],"minDate":timezone.now().date().strftime('%Y-%m-%d')}),
                    'delivery_time':forms.Select(choices=HOUR_CHOICES)}

修改完成后无需调整models、views层代码,用户提交已被占用的时段时,就会自动返回包含可用时段的错误提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 04:36:07