I am making a members management app. I have a activation form and I wrote a script to check if date is valid (clean_start_date & clean_end_date). ie todays date or greater. Script is working fine (if I select today's date or greater). However, if I selected an old date only end_date works fine, start_date Throws 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}")
Console Error Message
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
CodePudding user response:
The error you get is because the method clean_start_date()
is called on form validation, and this:
if start_date < timezone.now().date():
raise ValidationError('Please enter a valid start date!')
Excludes field from data validation, making this form invalid. This is why probably you don't get data in self.cleaned_field['start_date']
Also I don't really get why you call clean_start_date
twice - this method is called once in invisible way by form, second by you. When you write clean_FIELD_NAME
methods they are called directly by Django form logic.
So... the simple, and most obvious way to fix your issue is to write clean_end_date()
method correctly, without calling clean methods:
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
Update - the correct way of cleaning multiple field data with possible raises is (I did not noticed the dict value call...):
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