如何让Django ModelForm接受'%I:%M %p'格式的时间输入?
Django表单时间格式验证问题解决方法
问题描述
我在验证Django表单时遇到问题,表单代码如下:
class reservaForm(forms.ModelForm): class Meta: model = Reservas fields = '__all__' widgets = { 'guests': forms.NumberInput(attrs={'id':'id_invitados','min':'0','class':'form-control form-control-solid'}), 'date': forms.TextInput(attrs={'id':'date','class':'form-control form-control-solid flatpickr-input'}), 'timestarts': forms.TimeInput(format='%I:%M %p',attrs={'id':'id_time_starts','type':'time','class':'form-control form-control-solid','readonly':'readonly','onchange':'ajustarHora()'}), 'timeends': forms.TimeInput(format='%I:%M %p',attrs={'id':'id_time_ends','type':'time','class':'form-control form-control-solid','readonly':'readonly'}), }
使用JavaScript日历组件实现UI后,提交表单时出现错误:
hora_inicio
Enter a valid time.
表单提交的时间值为'5:30 PM',但无法被识别为有效格式。
解决方法
1. 移除原生时间输入类型冲突
浏览器的type='time'属性会强制使用24小时制的原生时间输入格式,和JS组件返回的12小时带AM/PM的格式冲突。需要移除widget中的type='time'属性:
'timestarts': forms.TimeInput(format='%I:%M %p',attrs={'id':'id_time_starts','class':'form-control form-control-solid','readonly':'readonly','onchange':'ajustarHora()'}), 'timeends': forms.TimeInput(format='%I:%M %p',attrs={'id':'id_time_ends','class':'form-control form-control-solid','readonly':'readonly'}),
2. 配置Django时间字段支持12小时格式
Django默认的TimeField只识别24小时制格式(如17:30),需要明确指定支持12小时带AM/PM的格式。在表单类中添加初始化方法:
class reservaForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 让字段同时支持12小时制和24小时制格式 self.fields['timestarts'].input_formats = ['%I:%M %p', '%H:%M'] self.fields['timeends'].input_formats = ['%I:%M %p', '%H:%M'] class Meta: model = Reservas fields = '__all__' widgets = { 'guests': forms.NumberInput(attrs={'id':'id_invitados','min':'0','class':'form-control form-control-solid'}), 'date': forms.TextInput(attrs={'id':'date','class':'form-control form-control-solid flatpickr-input'}), 'timestarts': forms.TimeInput(format='%I:%M %p',attrs={'id':'id_time_starts','class':'form-control form-control-solid','readonly':'readonly','onchange':'ajustarHora()'}), 'timeends': forms.TimeInput(format='%I:%M %p',attrs={'id':'id_time_ends','class':'form-control form-control-solid','readonly':'readonly'}), }
3. 自定义验证(可选)
如果需要更灵活的验证逻辑,可以重写表单的clean方法:
from datetime import datetime class reservaForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['timestarts'].input_formats = ['%I:%M %p', '%H:%M'] self.fields['timeends'].input_formats = ['%I:%M %p', '%H:%M'] class Meta: model = Reservas fields = '__all__' widgets = { 'guests': forms.NumberInput(attrs={'id':'id_invitados','min':'0','class':'form-control form-control-solid'}), 'date': forms.TextInput(attrs={'id':'date','class':'form-control form-control-solid flatpickr-input'}), 'timestarts': forms.TimeInput(format='%I:%M %p',attrs={'id':'id_time_starts','class':'form-control form-control-solid','readonly':'readonly','onchange':'ajustarHora()'}), 'timeends': forms.TimeInput(format='%I:%M %p',attrs={'id':'id_time_ends','class':'form-control form-control-solid','readonly':'readonly'}), } def clean_timestarts(self): time_str = self.cleaned_data.get('timestarts') if not time_str: return time_str try: return datetime.strptime(time_str, '%I:%M %p').time() except ValueError: try: return datetime.strptime(time_str, '%H:%M').time() except ValueError: raise forms.ValidationError("请输入有效的时间格式,如'5:30 PM'或'17:30'") def clean_timeends(self): time_str = self.cleaned_data.get('timeends') if not time_str: return time_str try: return datetime.strptime(time_str, '%I:%M %p').time() except ValueError: try: return datetime.strptime(time_str, '%H:%M').time() except ValueError: raise forms.ValidationError("请输入有效的时间格式,如'5:30 PM'或'17:30'")
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

