Skip to main content
 首页 » 编程设计

python之将 Django 从 1.9 迁移到 1.11 : trouble with MultiValueField and MultiWidget behaviour

2024年08月19日37oomusou

这是在 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 ] 

在 Django 1.11 中,它不再有效,ValidationError 总是被引发。 datalist 始终是一个仅包含 False 的列表。 永远不会调用decompress 方法。

我尝试按照非常旧的帖子中的建议实现 value_from_datadict 方法,但没有成功。

我看了一下Djando代码,好像Django不喜欢字段的结果(compress的返回值)是一个列表,所以我试着把它转换成一个字符串(作为逗号连接值)。但行为保持不变。

有什么想法吗?

编辑: 查看 HTML 源代码,子部件似乎没有正确呈现:它们都具有相同的名称,并且没有 ID。假设字段名称是 Valeurs:

在 Django 1.9 中,HTML 是:

<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" /> ... 

在 Django 1.11 中,HTML 是:

<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 />  

我有其他的 MultiValueField/MultiWidget 可以正常工作,写法非常相似。我真的不明白问题出在哪里。

请您参考如下方法:

这是发行说明所说的

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