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
相关产品推荐
相关产品推荐

