#28443: MultiValueField does not work with ModelChoiceField?
---------------------------+--------------------------------------
     Reporter:  adam-kral  |                    Owner:  nobody
         Type:  Bug        |                   Status:  closed
    Component:  Forms      |                  Version:  1.11
     Severity:  Normal     |               Resolution:  needsinfo
     Keywords:             |             Triage Stage:  Unreviewed
    Has patch:  0          |      Needs documentation:  0
  Needs tests:  0          |  Patch needs improvement:  0
Easy pickings:  0          |                    UI/UX:  0
---------------------------+--------------------------------------
Description changed by adam-kral:

Old description:

> The code: (where AddressInput is a MultiWidget)
>
> {{{#!python
> class AddressInput(widgets.MultiWidget):
>     def __init__(self, attrs=None):
>         self.widgets = widgets.HiddenInput(attrs),
> widgets.TextInput(attrs) # note that the second widget would be
> customized, I'm only providing simplified example, which does produce the
> same error
>         super().__init__(self.widgets, attrs)
>
>     def decompress(self, value):
>         try:
>             address = AddressPoint.objects.get(pk=value)
>         except (AddressPoint.DoesNotExist, ValueError):
>             address = None
>
>         return [value, str(address)]
>
>     def value_from_datadict(self, data, files, name):
>         return tuple(widget.value_from_datadict(data, files,
> f'{name}_{i}') for i, widget in enumerate(self.widgets))
>

> class AddressFormField(MultiValueField):
>     widget = AddressInput
>
>     def __init__(self, queryset, empty_label="---------",
> to_field_name=None, limit_choices_to=None, *args, **kwargs):
>         fields = (
>             ModelChoiceField(queryset, empty_label=empty_label,
> to_field_name=to_field_name, limit_choices_to=limit_choices_to, *args,
> **kwargs),
>             CharField()
>         )
>
>         super().__init__(fields=fields, require_all_fields=False, *args,
> **kwargs)
>
>         #self.widget.choices = self.fields[0].widget.choices  #### if not
> commented out, I get another error: AttributeError:
> 'RelatedFieldWidgetWrapper' object has no attribute 'decompress'
>
>     def compress(self, data_list):
>         if not data_list[1]:
>             return None
>
>         if not data_list[0]:
>             raise ValidationError('Invalid address')
>
>         return data_list[0]
>

> class AddressForeignKey(ForeignKey):
>     def formfield(self, **kwargs):
>         # This is a fairly standard way to set up some defaults
>         # while letting the caller override them.
>         defaults = {'form_class': AddressFormField}
>         defaults.update(kwargs)
>         return super().formfield(**defaults)
> }}}
> I get this error: AttributeError: 'AddressInput' object has no attribute
> 'choices'
> Because ModelChoiceField did not declare it. Passing the widget to
> ModelChoiceField does not work as it makes a copy if it's an instance.
> Thus I set the choices attribute manually as you can see in the commented
> out code.
> But then I got another error which I didn't resolve: AttributeError:
> 'RelatedFieldWidgetWrapper' object has no attribute 'decompress'

New description:

 The code: (where AddressInput is a MultiWidget)

 {{{#!python
 class AddressInput(widgets.MultiWidget):
     def __init__(self, attrs=None):
         self.widgets = widgets.HiddenInput(attrs),
 widgets.TextInput(attrs) # note that the second widget would be
 customized, I'm only providing simplified example, which does produce the
 same error
         super().__init__(self.widgets, attrs)

     def decompress(self, value):
         try:
             address = AddressPoint.objects.get(pk=value)
         except (AddressPoint.DoesNotExist, ValueError):
             address = None

         return [value, str(address)]


 class AddressFormField(MultiValueField):
     widget = AddressInput

     def __init__(self, queryset, empty_label="---------",
 to_field_name=None, limit_choices_to=None, *args, **kwargs):
         fields = (
             ModelChoiceField(queryset, empty_label=empty_label,
 to_field_name=to_field_name, limit_choices_to=limit_choices_to, *args,
 **kwargs),
             CharField()
         )

         super().__init__(fields=fields, require_all_fields=False, *args,
 **kwargs)

         #self.widget.choices = self.fields[0].widget.choices  #### if not
 commented out, I get another error: AttributeError:
 'RelatedFieldWidgetWrapper' object has no attribute 'decompress'

     def compress(self, data_list):
         if not data_list[1]:
             return None

         if not data_list[0]:
             raise ValidationError('Invalid address')

         return data_list[0]


 class AddressForeignKey(ForeignKey):
     def formfield(self, **kwargs):
         # This is a fairly standard way to set up some defaults
         # while letting the caller override them.
         defaults = {'form_class': AddressFormField}
         defaults.update(kwargs)
         return super().formfield(**defaults)
 }}}
 I get this error: AttributeError: 'AddressInput' object has no attribute
 'choices'
 Because ModelChoiceField did not declare it. Passing the widget to
 ModelChoiceField does not work as it makes a copy if it's an instance.
 Thus I set the choices attribute manually as you can see in the commented
 out code.
 But then I got another error which I didn't resolve: AttributeError:
 'RelatedFieldWidgetWrapper' object has no attribute 'decompress'

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/28443#comment:5>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.404f31899b55329935066b325bc382a1%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to