1

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?

Community
  • 1
  • 1
trubliphone
  • 4,132
  • 3
  • 42
  • 66
  • Aha! It turns out that clean has to return a "compressed" value. So the last line of clean ought to read: return "|".join(value) – trubliphone May 04 '12 at 20:33
  • `compress` and `clean` should always return something. I think "this field is required" means whole field, not just second part of it. – ilvar May 05 '12 at 04:47

1 Answers1

0

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)
trubliphone
  • 4,132
  • 3
  • 42
  • 66