At some point I need to display a "disabled"
(greyed out by disabled="disabled"
attribute) input of type "select"
. As specified in the standard (xhtml and html4), inputs of type "select"
can not have the "readonly"
attribute. Note that this is for presentation purposes only, the actual value must end up in the POST. So here is what I do (quoting a part of the form declaration in django):
from django import forms
_choices = ['to be', 'not to be']
class SomeForm(forms.Form):
field = forms.ChoiceField(choices=[(item, item) for item in _choices],
widget=forms.HiddenInput()) # the real field
mock_field = forms.ChoiceField(required=False, # doesn't get submitted
choices=[(item, item) for item in _choices],
label="The question",
widget=forms.Select(attrs={'disabled':'disabled'}))
Then it is initialized like this:
initial_val = 'to be'
form = SomeForm(ititial={'field':initial_val,
'mock_field':initial_val})
And all is well. Well, until the form gets validated and one of the other fields fails the validation. When this happens, the form is reloaded and the values are preserved, but not the one of the "mock_field" - it never got submitted (it is disabled). So it is not preserved. While this doesn't affect the data integrity, it is still not so good presentation-wise.
Is there any way to preserve that field, with as little hackery as possible? The form is a part of a django.contrib.formtools.FormWizard
and the initial values (and some fields) are generated dynamically. Basically, there is a lot of stuff going on already, it'd be great if it was possible not to overcomplicate things.
Browsers don't POST disabled fields.
You can try to copy field
s initial value to mock_field
in your Form's __init__
def __init__(self, *args, **kwargs):
super(SomeForm, self).__init__(*args, **kwargs)
mock_initial = self.fields['field'].initial
self.fields['mock_field'].initial = mock_initial
Code is not tested. Normally you would be concerned about form.data
as well, but in this case it won't be different than initial
Well, this will be the first time I answer my question, but I've found a solution and (while it cerainly is a hack) it works.
Instead of getting the initial value from the form instance, - self.fields['whatever'].initial
seems to be None
inside the constructor, I am getting the value from keyword argument "initial". And then I set it as the only choice for the "mock" field. Like this:
from django import forms
_choices = ['to be', 'not to be']
class SomeForm(forms.Form):
field = forms.ChoiceField(choices=[(item, item) for item in _choices],
widget=forms.HiddenInput()) # the real field
mock_field = forms.ChoiceField(required=False, # doesn't get submitted
choices=[(item, item) for item in _choices],
label="The question",
widget=forms.Select(attrs={'disabled':'disabled'}))
def __init__(self, *args, **kwargs):
super(SomeForm, self).__init__(*args, **kwargs)
mock_initial = kwargs['initial']['field']
self.fields['mock_field'].choices = [(mock_initial, mock_initial),]
This probably needs some error handling. Obviously, this will not work if the initial value is not provided for the actual field
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With