Migrating Django from 1.9 to 1.11: trouble with MultiValueField and MultiWidget behaviour

生来就可爱ヽ(ⅴ<●) 提交于 2020-01-15 01:51:18

问题


Here is a code that works as expected in Django 1.9:

class MultipleBooleanField(forms.MultiValueField):
    def __init__(self, *args, **kwargs):
        self.fieldnames = kwargs.pop('fields')
        fields = [ forms.BooleanField(required=False) for x in self.fieldnames ]
        super(MultipleBooleanField, self).__init__(fields=fields,
                            require_all_fields=False, *args, **kwargs)
        self.widget = MultipleBooleanWidget(widgets=[ f.widget for f in fields ])
        self.widget.fieldnames = self.fieldnames

    def compress(self, datalist):
        # return a list of the fieldnames, datalist is a list of booleans            
        print('compress datalist:', datalist)
        if self.required and not any(datalist):
            raise forms.ValidationError('You must choose at least one value')
        return [ self.fieldnames[i] for i in range(len(datalist)) if datalist[i] ]

class MultipleBooleanWidget(forms.MultiWidget):
    def render(self, name, value, attrs=None, renderer=None):
        if not value:
            value = [ False for x in self.fieldnames ]
        rendered_widgets = [ x.render(name, value[i]) for i,x in enumerate(self.widgets) ]
        items = [ '%s %s' % (rendered_widgets[i], f)
                                for (i,f) in enumerate(self.fieldnames) ]
        return ' '.join(items)

    def decompress(self, value):
        # return a list of booleans, value is a list of fieldnames
        print('decompress value:', value)
        if not value:
            return [ False for x in self.fieldnames ]
        return [ x in value for x in self.fieldnames ]

With Django 1.11, it no more works, the ValidationError is always raised. The datalist is always a list containing only False. The decompress method is never called.

I tried to implement a value_from_datadict method as suggested in very old posts, but no success.

I take a look to Djando code and it seems that Django does not like the result of the field (the return value of compress) to be a list, so I tried to transform it into a string (as comma joined values). But the behaviour remains the same.

Any ideas?

EDIT: Looking at the HTML source, it appears that subwidgets are not rendered correctly: they all have the same name, and have no id. Suppose the field name is Valeurs:

In Django 1.9, the HTML is:

<tr><th><label for="id_Valeurs_0">Valeurs :</label></th><td><input checked="checked" id="id_Valeurs_0" name="Valeurs_0" type="checkbox" /> Part du total com <input checked="checked" id="id_Valeurs_1" name="Valeurs_1" type="checkbox" /> Part du total Qté <input checked="checked" id="id_Valeurs_2" name="Valeurs_2" type="checkbox" /> ...

In Django 1.11, the HTML is:

<tr><th><label for="id_Valeurs_0">Valeurs :</label></th><td><input type="checkbox" name="Valeurs" checked /> Part du total com <input type="checkbox" name="Valeurs" checked /> Part du total Qté <input type="checkbox" name="Valeurs" checked /> 

I have others MultiValueField/MultiWidget that work correctly, written very similarly. I really don't understand where is the problem.


回答1:


Here is what the release notes say

The Widget.format_output() method is removed. Use a custom widget template instead.

https://docs.djangoproject.com/en/1.11/releases/1.11/#changes-due-to-the-introduction-of-template-based-widget-rendering




回答2:


I found the problem: it comes from the calculation of rendered_widgets in the render method, it must be:

rendered_widgets = [ x.render('%s_%d' % (name,i), value[i]) for i,x in enumerate(self.widgets) ]

With that solution, the rendered HTML has correct names, but still have no id. But it works.

I don't understand why django team removed the format_output method of MultiWidget: it was usefull, easy, high level. Having to deal with render is painful, but perhaps I missed something...



来源:https://stackoverflow.com/questions/46452755/migrating-django-from-1-9-to-1-11-trouble-with-multivaluefield-and-multiwidget

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!