#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 django-updates+unsubscr...@googlegroups.com. To post to this group, send email to django-updates@googlegroups.com. 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.