5

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

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

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

谢谢。

4

4 回答 4

5

没有简单的方法。您要么需要覆盖 the 的clean方法,MultipleChoiceField要么正如您在评论中提到的那样,使用 getlist 手动重新排序它们。这可能取决于您需要在代码中多久执行一次。

通过像这样通过运算符过滤对象列表来创建您正在接收的 a的clean方法,因此顺序由数据库给出:MultipleChoiceFieldQuerySetIN

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一个普通的列表。

于 2012-04-24T13:18:42.073 回答
0

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

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',)
        )
于 2016-03-03T16:43:42.343 回答
0

我是通过一个小部件做到的。它的好处是,它将以不同的语言正确排序:

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)
于 2017-01-07T22:52:21.617 回答
0

我可以使用以下方式维护选择的顺序:

class OrderedModelMultipleChoiceField(models.ModelMultipleChoiceField):

    def clean(self, value):
        qs = super(OrderedModelMultipleChoiceField, self).clean(value)
        preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(value)])
        return qs.filter(pk__in=value).order_by(preserved)

注意:我使用的是 Django 2.2

于 2021-05-22T08:51:29.460 回答