KeyError при выборе даты в прошлом

Я делаю приложение для управления членами. У меня есть форма активации и я написал скрипт для проверки правильности даты (clean_start_date & clean_end_date). т.е. сегодняшняя дата или больше. Скрипт работает нормально (если я выбираю сегодняшнюю дату или больше). Однако, если я выбрал старую дату, только end_date работает нормально, start_date бросает KeyError.

forms.py

class ActiveMemberForm(ModelForm):
    
    def __init__(self, *args, **kwargs):
        super(ActiveMemberForm, self).__init__(*args, **kwargs)
        pass
    
    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('Please enter a valid start date!')
        return start_date

        
    def clean_end_date(self):
        #start_date = self.cleaned_data['start_date']
        end_date = self.cleaned_data['end_date']
        if end_date < timezone.now().date() or end_date < self.clean_start_date():
            raise ValidationError('Please enter a valid end date!')
        return end_date

models.py

class ActiveMember(models.Model):
    member = models.OneToOneField(Member, on_delete=models.CASCADE, related_name='is_member')
    start_date = models.DateField(default=django.utils.timezone.now)
    end_date = models.DateField(default=django.utils.timezone.now)
    status = models.CharField(max_length=2, choices=(('1','Active'), ('2','Inactive')), default = '1', blank=True, null=True)
    
    def __str__(self): 
        return str(f"{self.member}")

Сообщение об ошибке консоли

Internal Server Error: /activate/
Traceback (most recent call last):
  File "C:\Users\timmeh\source\Python Projects\Django Projects\env\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "C:\Users\timmeh\source\Python Projects\Django Projects\env\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\timmeh\source\Python Projects\Django Projects\env\django_project\members\views.py", line 130, in activate
    if form.is_valid():
  File "C:\Users\timmeh\source\Python Projects\Django Projects\env\lib\site-packages\django\forms\forms.py", line 205, in is_valid
    return self.is_bound and not self.errors
  File "C:\Users\timmeh\source\Python Projects\Django Projects\env\lib\site-packages\django\forms\forms.py", line 200, in errors
    self.full_clean()
  File "C:\Users\timmeh\source\Python Projects\Django Projects\env\lib\site-packages\django\forms\forms.py", line 437, in full_clean
    self._clean_fields()
  File "C:\Users\timmeh\source\Python Projects\Django Projects\env\lib\site-packages\django\forms\forms.py", line 452, in _clean_fields
    value = getattr(self, "clean_%s" % name)()
  File "C:\Users\timmeh\source\Python Projects\Django Projects\env\django_project\members\forms.py", line 58, in clean_end_date
    if end_date < timezone.now().date() or end_date < self.clean_start_date():
  File "C:\Users\timmeh\source\Python Projects\Django Projects\env\django_project\members\forms.py", line 49, in clean_start_date
    start_date = self.cleaned_data['start_date']
KeyError: 'start_date'
[12/Aug/2022 14:55:53] "POST /activate/ HTTP/1.1" 500 89452

Скриншот отладочной программы KeyError enter image description here

Ошибка, которую вы получаете, связана с тем, что метод clean_start_date() вызывается при валидации формы, а это:

if start_date < timezone.now().date():
            raise ValidationError('Please enter a valid start date!')

Исключает поле из проверки данных, делая форму недействительной. Поэтому, вероятно, вы не получите данные в self.cleaned_field['start_date']

Также я не совсем понимаю, почему вы вызываете clean_start_date дважды - этот метод вызывается один раз невидимым образом формой, второй - вами. Когда вы пишете методы clean_FIELD_NAME, они вызываются непосредственно логикой формы Django.

Итак... простой и наиболее очевидный способ решить вашу проблему - написать clean_end_date() метод правильно, без вызова чистых методов:

        start_date = self.cleaned_data['start_date']
        end_date = self.cleaned_data['end_date']
        # not necessary data clean on start date field
        # if end_date < timezone.now().date() or end_date < self.clean_start_date():
        if end_date < timezone.now().date() or end_date < start_date:
            raise ValidationError('Please enter a valid end date!')
        return end_date

Обновление - правильным способом очистки данных нескольких полей с возможными повышениями является (я не заметил вызов значения dict...):

    def clean(self):
        start_date = self.cleaned_data['start_date']
        end_date = self.cleaned_data['end_date']
        if start_date < timezone.now().date():
            raise ValidationError('Please enter a valid start date!')
        if end_date < timezone.now().date() or end_date < start_date:
            raise ValidationError('Please enter a valid end date!')
        return self.cleaned_data
Вернуться на верх