选择过去日期触发KeyError(Django会员管理系统)
Django表单日期校验KeyError问题解决
问题根源
当start_date输入过去日期时,clean_start_date抛出ValidationError,Django会跳过将该字段加入cleaned_data的步骤。但clean_end_date中直接调用self.clean_start_date(),再次执行该方法时,尝试从无对应键的cleaned_data中取start_date,就会触发KeyError。
修复方案
方案1:修改clean_end_date方法,安全获取start_date
def clean_end_date(self): end_date = self.cleaned_data['end_date'] today = timezone.now().date() if end_date < today: raise ValidationError('请输入有效的结束日期!') # 用get方法避免KeyError,仅当start_date校验通过时才判断日期先后 start_date = self.cleaned_data.get('start_date') if start_date and end_date < start_date: raise ValidationError('结束日期不能早于开始日期!') return end_date
方案2:使用表单级clean方法(更推荐)
表单级clean方法在所有字段校验完成后执行,适合处理多字段关联校验,逻辑更清晰:
class ActiveMemberForm(ModelForm): def __init__(self, *args, **kwargs): super(ActiveMemberForm, self).__init__(*args, **kwargs) class Meta: model = ActiveMember fields = ('member', 'start_date', 'end_date', 'status') widgets = { 'start_date': widgets.DateInput(attrs={'type': 'date'}), 'end_date': widgets.DateInput(attrs={'type': 'date'}), } def clean_start_date(self): start_date = self.cleaned_data['start_date'] if start_date < timezone.now().date(): raise ValidationError('请输入有效的开始日期!') return start_date def clean_end_date(self): end_date = self.cleaned_data['end_date'] if end_date < timezone.now().date(): raise ValidationError('请输入有效的结束日期!') return end_date def clean(self): cleaned_data = super().clean() start_date = cleaned_data.get('start_date') end_date = cleaned_data.get('end_date') if start_date and end_date and end_date < start_date: self.add_error('end_date', '结束日期不能早于开始日期!') return cleaned_data
额外优化
模型中start_date和end_date的默认值用timezone.now()会生成datetime对象,与DateField类型不匹配,建议修改为:
start_date = models.DateField(default=lambda: timezone.now().date()) end_date = models.DateField(default=lambda: timezone.now().date())
内容的提问来源于stack exchange,提问作者wormy505
相关产品推荐
相关产品推荐

