-->

Django的MultipleChoiceField不保留选定值的顺序(Django Multipl

2019-09-16 16:49发布

我有一个Django的ModelForm它通过持有一个模型公开对应于许多一对多关系的选择题场order选择的(一个文件列表)作为额外的属性。 在前端,该字段被显示为两个多重选择字段中管理的相似,一个列出可用的选择,而另一个保持选定的元素。

该表格可以保存的元素的正确选用,但他们总是在选择原来的顺序,而不是选择的顺序。 浏览器将在正确的顺序选择,但为了form.cleaned_data['documents']总是在选择原订单的订单。

我怎样才能让MultipleChoiceField尊元素的顺序选择?

谢谢。

Answer 1:

有没有简单的方法。 你要么需要重写clean的方法MultipleChoiceField或者,当你在你的评论中提到,使用的GetList手动重新订购。 这可能取决于你的代码,你需要多久做。

clean的方法MultipleChoiceField创建QuerySet您收到,通过经由过滤对象列表IN操作者这样的,所以为了由数据库给出:

qs = self.queryset.filter(**{'%s__in' % key: value})

您可以从继承ModelMultipleChoiceField

class OrderedModelMultipleChoiceField(ModelMultipleChoiceField):
    def clean(self, value):
        qs = super(OrderedModelMultipleChoiceField, self).clean(value)
        return sorted(qs, lambda a,b: sorted(qs, key=lambda x:value.index(x.pk)))

其缺点是,返回值不再是一个QuerySet ,但一个普通的列表。



Answer 2:

要重写清洁方法也可以做到这一点时,返回的有序查询集:

class OrderedModelMultipleChoiceField(ModelMultipleChoiceField):
    def clean(self, value):
        qs = super(OrderedModelMultipleChoiceField, self).clean(value)
        clauses = ' '.join(['WHEN id=%s THEN %s' % (pk, i) for i, pk in enumerate(value)])
        return qs.filter(pk__in=value).extra(
            select={'ordering': 'CASE %s END' % clauses},
            order_by=('ordering',)
        )


Answer 3:

我通过一个Widget做到了。 它的好处是,它会在不同的语言正确排序:

class SortedSelectMultiple(SelectMultiple):

def render_options(self, selected_choices):
    self.choices = sorted(self.choices)
    self.choices.sort(key=lambda x: x[1])
    return super(SortedSelectMultiple, self).render_options(selected_choices)


文章来源: Django MultipleChoiceField does not preserve order of selected values