I have been subclassing multiwidget to create an HTML5 range slider synchronised with a NumberInput field using this code:
class SplitRangeNumberWidget(MultiWidget):
def __init__(self):
widgets = (
forms.NumberInput(attrs={'type':'range',
'onchange':'this.nextElementSibling.value=this.value',
'oninput':'this.nextElementSibling.value=this.value',
'step':'any',
'min':0,
'max':1}),
forms.NumberInput(attrs={'step':'any',
'onchange':'this.previousElementSibling.value=this.value',
'oninput':'this.previousElementSibling.value=this.value',})
)
super(SplitRangeNumberWidget, self).__init__(widgets)
def decompress(self, value):
if value:
return [value, value]
return [None, None]
When I instanciate it and use it in a Form such as:
class ParameterForm(forms.ModelForm):
class Meta:
model = Parameter
fields = ['name','value','min_value','max_value']
widgets = {'value':SplitRangeNumberWidget()}
, the widget works fine: changing the slider or the numberinput does change the other field. However, when doing a POST, the form does not validate and I get this error in form.errors (for 3 parameters):
[{'value': ['Enter a number.']}, {'value': ['Enter a number.']}, {'value': ['Enter a number.']}]
The widgets alone do work well and form is correctly bound. But not in a multiwidget. What am I doing wrong? I added
def value_from_datadict(self, data, files, name):
num = [widget.value_from_datadict(data, files, name + '_%s' % i)
for i, widget in enumerate(self.widgets)]
return [float(num[0]), float(num[1])]
but this still does not work.
Thanks for your help.
I found the solution: I needed to implement
To paraphrase the documentation: The default implementation of value_from_datadict() returns a list of values corresponding to each Widget. This is appropriate when using a MultiWidget with a MultiValueField, but since we want to use this widget with a TextField which takes a single value, we have overridden this method to combine the data of all the subwidgets into a value.