In my Django app (v. 3.1), I've added a custom form to trigger a data export that, among other things, can collect two integer values that represent years in a date range. When the form is submitted, no matter what values the user has set in the number fields, the values that appear in the form's cleaned_data
attribute are the values that were set as initial
for those fields on the definition of the form class.
For example, the initial value of the field should be 2022
- but no matter what value the user sets in the input, the value in form.cleaned_data
for the field is 2022
.
A ChoiceField
in the form works as expected, and I'm pretty inexperienced with Django - so I can't quite figure out what I've done wrong here. Here's a slightly simplified version of the code...
observation/forms.py
:
from django import forms
import datetime
export_formats = [
'csv',
'xls',
'xlsx',
]
export_format_choices = [(f, f) for f in export_formats]
min_year = 1950
class ExportForm(forms.Form):
current_year = datetime.datetime.now().year
export_format = forms.ChoiceField(required=True, label='Format', choices=export_format_choices)
year_from = forms.IntegerField(required=False, disabled=True, min_value=min_year, max_value=current_year, initial=current_year)
year_through = forms.IntegerField(required=False, disabled=True, min_value=min_year, max_value=current_year, initial=current_year)
def __init__(self, *args, **kwargs):
super(ExportForm, self).__init__(*args)
admin.py
def export_view(self, request):
if request.method == 'POST':
form = ExportForm(request.POST)
if form.is_valid():
export_format = form.cleaned_data['export_format']
data_scope = 'all'
year_range = ''
year_range = f'_{form.cleaned_data["year_from"]}-{form.cleaned_data["year_through"]}'
query_params &= Q(created_at__year__gte=form.cleaned_data['year_from'])
query_params &= Q(created_at__year__lte=form.cleaned_data['year_through'])
query = Observation.objects.filter(query_params).select_related('items')
dataset = ObservationResource().export(query)
response = HttpResponse(getattr(dataset, export_format), content_type=export_format)
response['Content-Disposition'] = f'attachment; filename="items_data_{data_scope}{year_range}.{export_format}"'
return response
return TemplateResponse(request, 'export.html')
So the line form.cleaned_data['export_format']
in admin.py
is set to the correct value - and if I examine form.POST
, I can see the correct values for year_from
and year_through
being set (in this case, 2019 and 2020) -
<QueryDict: {'csrfmiddlewaretoken': ['...'], 'year_from': ['2019'], 'year_through': ['2020'], 'export_format': ['csv']}>
but the cleaned_data
appears as
{'export_format': 'csv', 'year_from': 2022, 'year_through': 2022}
Why is it that the cleaned_data
for these IntegerField
s does not reflect the data in form.POST
? Thanks much.
CodePudding user response:
In your form definition you have
year_from = forms.IntegerField(required=False, disabled=True,
From the docs
The disabled boolean argument, when set to True, disables a form field using the disabled HTML attribute so that it won’t be editable by users. Even if a user tampers with the field’s value submitted to the server, it will be ignored in favor of the value from the form’s initial data.
If you want users to be able to edit the value, removing this attribute should do the trick.