Django custom form – cleaned_data has incorrect values for IntegerField

Question:

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 IntegerFields does not reflect the data in form.POST? Thanks much.

Asked By: skwidbreth

||

Answers:

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.

Answered By: SamSparx
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.