MultiValueField不适用于ModelChoiceField

时间:2017-07-27 22:32:55

标签: python django django-forms django-1.11

代码:(其中AddressInput是MultiWidget)

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)

我收到此错误:AttributeError:'AddressInput'对象没有属性'choices' 因为ModelChoiceField没有声明它。将小部件传递给ModelChoiceField不起作用,因为它是一个副本,如果它是一个实例。 因此,我可以手动设置choices属性,如您在注释掉的代码中所看到的那样。 但后来我得到了另一个我没有解决的错误:AttributeError:'RelatedFieldWidgetWrapper'对象没有属性'解压缩'

1 个答案:

答案 0 :(得分:0)

你想把它变成Django中的Widget吗?

<input type="text" name="example" list="exampleList">
<datalist id="exampleList">
  <option>hello</option>
  <option>there</option>
</datalist>

如果你这样做,你可以检查一下。

class ListTextWidget(forms.TextInput):
    def __init__(self, data_list, name, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._name = name
        self._list = data_list
        self.attrs.update({'list':'list_%s' % self._name, 'autocomplete':'off'})

    def render(self, name, value, attrs=None):
        text_html = super().render(name, value, attrs=attrs)
        data_list = '<datalist id="list_%s">' % self._name
        for item in self._list:
            data_list += '<option value="%s">' % item
        data_list += '</datalist>'

        return (text_html + data_list)


class ExampleForm(ModelForm)
    ...
    include = ['exampleOne', ...]
    widgets = { 
    'exampleOne': ListTextWidget(data_list=yourModel.objects.all(),name='exampleOne')
    }