Form submit with initially disabled field loses data

I have a form where one field is initially disabled, but the front end can enable it under certain conditions.

Data is received to the backend upon submission, but it seems the form still thinks it is disabled, and this code from the BaseForm class kicks in:

    def _clean_fields(self):
        for name, bf in self._bound_items():
            field = bf.field
            value = bf.initial if field.disabled else bf.data

(https://github.com/django/django/blob/3f8dbe267d35f0219277f0fe2d79915a4fb2b045/django/forms/forms.py#L331)

This causes the cleaned value to be set to None which was the initial form value.

How can I tell the clean method on my own form (a ModelForm) that this field was actually enabled and the submitted value should be taken, and not the initial value?

You can’t - by the time you get to the clean method, it’s too late.

If a field is identified as disabled, the binding operation is going to ignore the submitted field.

The form would need to be bound with the data for you to process it at all.

I’m not sure I understand if these conditions that may allow this field to be enabled are part of the same page or from an earlier page. If it’s data being carried over from a previous page, you can alter the field in the form at the time the instance is being created. If it’s activity being performed on that page, then it’s significantly more difficult.

I would suggest you invert the logic internally. Enable the field in the form itself, then disable that field as part of the GET for that form. Then, on the POST, check to see if the appropriate conditions are met. If they are not, then ignore the data from that field.

I’m not quite sure I understand the response here. Do you mean that we can never have any js on a page that will flip the disabled flag on a field depending on what other fields change? That seems like fairly common functionality that I should be able to handle.

Initially, the field is disabled, but if the user changes the value of a select field in the form, it should become enabled. The problem is that the initial disabled state is always used rather than the state when the form was actually submitted.

Or perhaps I’m misunderstanding your answer here?

I’m not saying that at all.

What I’m saying is that you want the field defined as enabled within the form, and then handle the case where it’s disabled as opposed to defining it as disabled at start.

Your other option would be to interrogate the POST data before binding the form to make that determination at the time the form instance is created, allowing you to set the state of that field when it’s bound.

The point is, when you say:
form = MyForm(request.POST)
it’s at that point in time where the field needs to be enabled. By the time you get to the “clean” process, it’s too late.

1 Like

Ah, gotcha. SOrry, my misunderstanding :slight_smile:

Yes, changing so the form thinks it’s enabled and just doing the dis/enabling in the template means it should always get the value (although in some cases it probably shouldn’t, but obviously that’s easier to code for).

Thanks for the help!

1 Like