5

order選択(ドキュメントのリスト)を追加の属性として保持するモデルを介して、多対多の関係に対応する複数選択フィールドを公開するDjangoModelFormがあります。フロントエンドでは、フィールドはadminと同様の2つの複数の選択フィールドとして表示されます。1つは使用可能な選択肢を一覧表示し、もう1つは選択した要素を保持します。

フォームは要素を正しく選択して保存できますが、それらは常に選択ではなく、元の選択の順序になっています。ブラウザは選択範囲を正しい順序で送信しますが、順序form.cleaned_data['documents']は常に元の選択順序です。

MultipleChoiceFieldが選択された要素の順序を尊重するようにするにはどうすればよいですか?

ありがとう。

4

4 に答える 4

5

簡単な方法はありません。cleanのメソッドをオーバーライドするかMultipleChoiceField、コメントで述べたように、getlist を使用して手動で並べ替える必要があります。おそらく、コード内でそれを行う必要がある頻度によって異なります。

cleanメソッドは、次のような演算子を使用してオブジェクト リストをフィルタリングすることにより、受け取った をMultipleChoiceField作成するため、データベースによって順序が指定されます。QuerySetIN

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

ウィジェット経由で行いました。その利点は、さまざまな言語で適切にソートされることです。

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

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 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 に答える