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

Django TimeField输入24:00报错咨询:Cannot use None as a query value

问题分析与解决方案

问题根源

Python的datetime.time类型仅支持00:00到23:59的时间范围,无法解析24:00。当用户输入24:00时,Django无法将其转换为有效的Time对象,导致from_hour或to_hour字段值变为None。后续在clean方法的查询过滤器中使用该None值,就会抛出Cannot use None as a query value错误。

解决步骤

1. 处理24:00的输入映射

首先要把用户输入的24:00转换为Django能识别的time(0, 0),避免字段值为None。推荐在表单层面处理(更精准),如果使用ModelForm,添加字段清洗方法:

from django import forms
from .models import OpeningHours
import datetime

class OpeningHoursForm(forms.ModelForm):
    class Meta:
        model = OpeningHours
        fields = ['user', 'pitche', 'made_on', 'from_hour', 'to_hour', 'timing']
    
    def clean_from_hour(self):
        from_hour_str = self.data.get('from_hour')
        if from_hour_str == '24:00':
            return datetime.time(0, 0)
        return self.cleaned_data.get('from_hour')
    
    def clean_to_hour(self):
        to_hour_str = self.data.get('to_hour')
        if to_hour_str == '24:00':
            return datetime.time(0, 0)
        return self.cleaned_data.get('to_hour')

如果不想修改表单,也可以在模型的clean方法开头处理(依赖Django解析失败后的None值):

def clean(self):
    # 处理24:00输入导致的None值
    import datetime
    if self.from_hour is None:
        self.from_hour = datetime.time(0, 0)
    if self.to_hour is None:
        self.to_hour = datetime.time(0, 0)
    
    # 原有验证逻辑...

2. 修改时间段冲突检测逻辑

由于time(0, 0)现在代表当天的24:00,需要调整冲突查询条件,确保重叠检测正确。修改模型的clean方法中的查询部分:

def clean(self):
    import datetime
    from django.db.models import Q

    # 处理24:00输入的None值(如果没在表单处理的话)
    if self.from_hour is None:
        self.from_hour = datetime.time(0, 0)
    if self.to_hour is None:
        self.to_hour = datetime.time(0, 0)

    # 原有基础验证
    if self.from_hour == self.to_hour:
        raise ValidationError('Wrong Time')
    if self.made_on < datetime.date.today():
        raise ValidationError('Invalid Date')

    # 构建冲突查询条件
    conflict_conditions = Q()
    if self.to_hour == datetime.time(0, 0):
        # 当前预订结束于当天24:00(次日00:00),冲突条件:现有预订的结束时间晚于当前开始时间,或现有预订也结束于当天24:00
        conflict_conditions = Q(to_hour__gt=self.from_hour) | Q(to_hour=datetime.time(0, 0))
    else:
        # 当前预订结束于当天非24:00时间,冲突条件:原有重叠逻辑 + 结束于当天24:00且开始时间早于当前结束时间的预订
        conflict_conditions = (
            Q(to_hour__gt=self.from_hour, from_hour__lt=self.to_hour) |
            Q(to_hour=datetime.time(0, 0), from_hour__lt=self.to_hour)
        )

    # 检查冲突
    if OpeningHours.objects.exclude(pk=self.pk).filter(
        made_on=self.made_on,
        pitche_id=self.pitche_id,
        conflict_conditions
    ).exists():
        # 提示时把00:00转回24:00,符合用户认知
        end_time = "24:00" if self.to_hour == datetime.time(0, 0) else self.to_hour
        raise ValidationError(
            f'The booked time ({self.from_hour} to {end_time}) is occupied.'
        )
    
    return super().clean()

额外说明

  • 前端时间选择器需要允许用户选择24:00,确保提交的是字符串"24:00",这样表单清洗方法能精准识别转换。
  • 转换后的time(0, 0)在数据库中存储为00:00,但在给用户的提示中要转回24:00,避免认知混淆。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:14:52