disabled field is not passed through - workaround needed

I used jQuery to solve the problem by removing disabled from all inputs before submitting.

$('#my_form').submit(function(){
    $("#my_form :disabled").removeAttr('disabled');
});

Used answer from another SO answer


I had a little fun looking into how forms works and came up with multiple solutions, just for the heck of it.

Since you are disabling the widget and not the field, as far as the form is concerned it's always receiving nothing for fieldA and that will always fail validation.

Trying something in the clean() method won't help for invalid forms because clean() data is for processing.

It looks like the way forms pull data for HTML display is field.data, which is a call to field.widget.value_from_datadict(POST, FILES, field_name) so it will always be looking at your POST data.

So I think you have a few options. Hack request.POST, hack the internal form POST data, or hack value_from_datadict.


Hacking request.POST: straight forward, makes sense.

    myModelobject = get_object_or_404(MyModel.objects, pk=mymodel_id)

        if request.method == 'POST':
            POST = request.POST.copy()
            POST['fieldA'] = myModelobject.fieldA
            model_form = MyModelUpdateForm(POST, instance=myModelobject )

            if model_form .is_valid():
                # ...

Hacking internal dictionary:

def __init__(self, *args, **kwargs):
    super(MyModelUpdateForm, self).__init__(*args, **kwargs)
    self.data.update({ 'fieldA': self.instance.fieldA })

Hacking value_from_datadict: kinda ridiculous, but illustrates what you can learn from digging into the source

def __init__(self, *args, **kwargs):
    super(MyModelUpdateForm, self).__init__(*args, **kwargs)
    self.fields['fieldA'].widget.value_from_datadict = lambda *args: self.instance.first_name

Learned some cool things here : ) Hope it helps.


You can put it in the form class like this:

class MyForm(forms.Form):

    MY_VALUE = 'SOMETHING'
    myfield = forms.CharField(
        initial=MY_VALUE,
        widget=forms.TextInput(attrs={'disabled': 'disabled'})

    def __init__(self, *args, **kwargs):

        # If the form has been submitted, populate the disabled field
        if 'data' in kwargs:
            data = kwargs['data'].copy()
            self.prefix = kwargs.get('prefix')
            data[self.add_prefix('myfield')] = MY_VALUE
            kwargs['data'] = data

        super(MyForm, self).__init__(*args, **kwargs) 

The way it works, is it tests to see if any data has been passed in to the form constructor. If it has, it copies it (the uncopied data is immutable) and then puts the initial value in before continuing to instantiate the form.