Reputation: 11
So I am currently working on the project in Django. The user should be able to set start date and the end date, based on this set interval an analysis should be calculated.
The current problem is, when the data comes to validation, it sees input data as an NoneType.
Note: I did not upload the entire html code. Only form relevant code.
forms.py
from django import forms
from tempus_dominus.widgets import DatePicker
import datetime
class AnalysisInformationForm(forms.Form):
start = forms.DateField(help_text="Enter a date between 2019-03-01 and now.",
input_formats=["%d/%m/%Y"],
widget=DatePicker(
options={
'minDate': '2019-03-01',
'maxDate': datetime.datetime.utcnow().date().strftime("%Y-%m-%d")
})
)
end = forms.DateField(help_text="Enter a date between the chosen start date and now",
input_formats=["%d/%m/%Y"],
widget=DatePicker(
options={
'minDate': '2019-03-01',
'maxDate': datetime.datetime.utcnow().date().strftime("%Y-%m-%d")
})
)
def clean(self):
cleaned_data = super(AnalysisInformationForm, self).clean()
start = cleaned_data.get('start')
end = cleaned_data.get('end')
print(start, end)
if start >= end:
raise forms.ValidationError('Invalid dates input. The start day must be set earlier than the end date. ')
return cleaned_data
views.py
def index(request):
if request.method == 'POST':
form = AnalysisInformationForm(request.POST)
if form.is_valid():
pass
else:
form = AnalysisInformationForm()
return render(request, 'stm/index.html', {'form': form})
index.html
<head>
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.css">
<link rel="stylesheet" href="{% static 'css/bootstrap.css' %}"><link>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
</head>
{{ form.media }}
<body>
<div class="form-group"></div>
{% load widget_tweaks %}
<form method="post" novalidate>
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
<div class="input-group">
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
<div class="input-group m-3">
<input type="submit" class="btn btn-outline-secondary btn-block" value="Continue">
</div>
</form>
</body>
These tutorials brought me to this solution:
https://pypi.org/project/django-tempus-dominus/
https://pypi.org/project/django-widget-tweaks/
I also found a similar question on stack overflow, though no answer: Django DateField form generates None in cleaned_data
I also tried to do the following to check whether the actual data is coming through. so in views.py I've changed the following: Before:
form = AnalysisInformationForm(request.POST)
After:
form = request.POST['start']
print(form)
In between the Errors I found that print statement. And surprise, surprise, the given start date did match the actual input. But after the data has been cleaned it becomes a NoneType value.
Any suggestions what might be the cause?
The expected result is for the data to be able to get validated as shown in the code. The start date must be set earlier than the end date and if not show the error message.
Upvotes: 0
Views: 989
Reputation: 11
So after trying several things. I've come to the following solution: Firstly in forms.py I've updated the clean function to match the following. Found this clean function somewhere here on stackoverflow, but forgot to save the link to it, didn't know if this would work:
def clean(self):
data = self.cleaned_data
print(data)
start = data.get('start')
end = data.get('end')
if start >= end:
raise forms.ValidationError('Invalid dates input. The start day must be set earlier than the end date. ')
return data
Then I tried several date input formats, such as ["%y/%m/%d"](19/04/02 format, not iso), ["%Y/%m/%d"](2019/04/02 format, not iso), ["%y-%m-%d"](19-04-02 format, not iso), ["%Y-%m-%dT%H:%M:%S.%fZ"](well, iso datetime format, but I'm working with date objects not datetime objects). So I've come to conclusion that I just have to change the / to - in ["%Y/%m/%d"] and everything should work. And it actually did work :D
This is how the new updated form class looks like:
class AnalysisInformationForm(forms.Form):
start = forms.DateField(help_text="Enter a date between 2019-03-01 and now.",
input_formats=["%Y-%m-%d"],
widget=DatePicker(
options={
'minDate': '2019-03-01',
'maxDate': datetime.datetime.utcnow().date().strftime("%Y-%m-%d")
})
)
end = forms.DateField(help_text="Enter a date between the chosen start date and now",
input_formats=["%Y-%m-%d"],
widget=DatePicker(
options={
'minDate': '2019-03-01',
'maxDate': datetime.datetime.utcnow().date().strftime("%Y-%m-%d")
})
)
Thanks to everyone who tried to help, you helped me find the right solution.
Upvotes: 1
Reputation: 5854
for django 2.1 try this
def clean(self):
cleaned_data = super().clean()
start = cleaned_data.get("start")
end = cleaned_data.get("end")
hope it helps
Upvotes: 0
Reputation: 367
Try to find what passed to the clean() method before the super() is called. Perhaps it comes from client in non-iso format and did not pass the default validation from superclass
Upvotes: 0
Reputation: 63
may be you need to make " post " in html all uppercase
<form method="POST" novalidate>
Upvotes: 0