Django MultipleChoiceField不保留所选值的顺序

时间:2012-04-24 10:43:21

标签: django django-forms cleaned-data

我有一个Django ModelForm,它通过一个模型来公开一个对应于多对多关系的多选字段,该模型将order选择(文档列表)作为额外属性。在前端,该字段显示为两个与admin中类似的多个选择字段,一个列出可用选项,另一个列出所选元素。

表单可以使用正确的元素选择进行保存,但它们始终按原始选择顺序排列,而不是选择顺序。浏览器以正确的顺序发送选择,但form.cleaned_data['documents']中的顺序始终是原始顺序的顺序。

如何使MultipleChoiceField尊重所选元素的顺序?

感谢。

3 个答案:

答案 0 :(得分:5)

没有简单的方法。您需要覆盖clean的{​​{1}}方法,或者如您在评论中提到的那样,使用getlist手动重新排序。这可能取决于您需要在代码中执行的频率。

MultipleChoiceField 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))) ,而是普通列表。

答案 1 :(得分:0)

要在覆盖clean方法时返回有序的QuerySet,您也可以这样做:

with a as (
      select a.col1, a.col2, a.col3, a.col4 from data 
     )
select a.col1, a.col2, a.col3, a.col4
from a
union all
select NULL, NULL,
       sum(case when a.col2 = 'BBB' then a.col3 
                when a.col2 = 'CCC' then - a.col3
            end),
       sum(case when a.col2 = 'BBB' then a.col4
                when a.col2 = 'CCC' then - a.col4
            end)
from a;

答案 2 :(得分:0)

我通过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)