django multivaluefield & multiwidget - make one optional

1.7k Views Asked by At

This is related to an earlier question of mine.

I want to have a MultiValueField which contains a Choice and TextInput widget. If the user selects "OTHER" from the Choice, then the value of the TextInput should be saved. Otherwise, the value of the Choice should be saved. So far I have the following code:

custom_choices = [("one","one"),("two","two"),("OTHER","OTHER")]

class MyMultiWidget(forms.MultiWidget):
    def __init__(self,*args,**kwargs):
        widgets = (
            forms.Select(choices=custom_choices),
            forms.TextInput(),
        )
        super(MyMultiWidget, self).__init__(widgets,*args,**kwargs)

    def decompress(self, value):
        if value:
             return value.split("|")
        return ['', '']

class MyMultiValueField(forms.MultiValueField):
    def __init__(self, *args, **kwargs):
        fields = (
            forms.CharField(max_length=128,required=True),
            forms.CharField(max_length=128,required=False),
        )
        super(MyMultiValueField, self).__init__(fields, *args, **kwargs)
        self.widget = TestMultiWidget()

    def compress(self, data_list):
        if data_list:
            return '|'.join(data_list)

class MyTestField(models.CharField):
    def formfield(self, **kwargs):
        return super(MyTestField, self).formfield(form_class=MyMultiValueField)

class MyModel(models.Model):
    myField = MyTestField()

However, whenever I try to save something which doesn't contain a value in the TextInput, I get a validation error "This field is required." This is in spite of the "required=False" kwarg above.

I have tried to add some logic to the clean function; ignore the TextInput's widget if the Choice widget's value is "OTHER":

def clean(self,value):
    if value[0]!="OTHER":
        value[1]=u''
    else:
        if not value[1]:
            msg = "unspecified value"
            raise forms.ValidationError(msg)
        elif "|" in value[1]:
            msg = "bad value ('|' character is not allowed"
            raise forms.ValidationError(msg)
    super(TestFormField,self).clean(value)

But this has no effect.

Any suggestions?

1

There are 1 best solutions below

0
On BEST ANSWER

The correct version of clean ought to look like this:

def clean(self,value):
    if value[0] != "OTHER":
        value[1] = u' '
    else:
        if value[1].strip() == u' ':
            msg = "unspecified value"
            raise forms.ValidationError(msg)
        elif "|" in value[1]:
            msg = "bad value ('|' character is not allowed)"
            raise forms.ValidationError(msg)
    return "|".join(value)