8

モデルフォームセットを表示していますが、フォームをそのフィールドの1つのコンテンツで並べ替えたいと思います。SomeModel.objects.filter(whatever).order_by('somefield')したがって、テンプレートの(モデル)フォームセットに相当するものを使用したいと思います。

これどうやってするの?

can_orderそれは私が望むことをしないことに注意してください(それは自動でなければならず、ユーザー指定ではありません)。dictsortフィルターのような他のことも試しましたが、それは予測できない出力を生成します(つまり、指定されたフィールドで順序付けられていません)。

私も試し{% regroup formset by somefield as sorted_formset %}ましたが、結果sorted_formsetは通常のフォームセットとして使用(反復)できません。

4

5 に答える 5

7

Formset を定義していない場合、これは「インライン コード」バージョンです。

FS=inlineformset_factory(ParentClass,ChildClass)
formset=FS(instance=parentobject,
           queryset=parentobject.childobject_set.order_by("-time_begin")
          )
于 2015-08-05T14:54:02.563 に答える
7

答えを完成させる。フォームセット内のフォームの順序を制御する方法は 2 つあります。別の方法 (フォームの順序を完全に制御したい場合) は、カスタム フォームセット クラスとオーバーライド__iter__および__getitem__メソッドを定義することです。

from django.forms import BaseModelFormSet

class MyModelBaseFormset(BaseModelFormSet):
    def __iter__(self):
        """Yields the forms in the order they should be rendered"""
        return ...

    def __getitem__(self, index):
        """Returns the form at the given index, based on the rendering order"""
        return ...


MyModelFormset = modelformset_factory(model=MyModel, formset=MyModelBaseFormset, queryset=...)

このアプローチは、Django のドキュメントで説明されています。

フォームセットを反復処理すると、作成された順序でフォームがレンダリングされます。メソッドの代替実装を提供することで、この順序を変更できます__iter__()

フォームセットにインデックスを付けることもできます。これにより、対応するフォームが返されます。をオーバーライドする場合は、動作を一致__iter__させるためにもオーバーライドする必要があります 。__getitem__

https://docs.djangoproject.com/en/dev/topics/forms/formsets/#django.forms.formsets.BaseFormSet

これらのメソッドを実装する例は、たとえば次の SO スレッドにあります: modelformset __iter__ overloading problem

于 2017-05-03T20:33:27.560 に答える
5

上記の@john-petersの回答に感謝します。私を正しい方向に向けてくれました。しかし、より良い方法は次のとおりです。

MyFormset(inlineformset_factory(...)):

  def get_queryset(self):
    return super(MyFormset, self).get_queryset().order_by('myfieldname')

この方法では、django のコードをコピーしたりいじったりする必要がなく、途中で破損する可能性があります。django が提供するクエリセットを取得して、順序をオーバーライドするだけです。私はこれを自分のコードで使用しましたが、動作します。

編集。これに少し取り組んだ後、正常に動作しているように見えますが、BaseInlineFormset.get_queryset() のロジックが何らかの形で台無しになり、データベース クエリが重複していることに気付きました。ただし、誰かがこれについてコメントして修正することを期待して、ここに残しておきます。一方、次のように、機能し、冗長なクエリが発生しない別のソリューションがあります。

MyFormset(inlineformset_factory(...)):
    def __init__(self, *args, **kwargs):
        super(MyFormset, self).__init__(*args, **kwargs)
        self.queryset = self.queryset.order_by('myfieldname')

これにより、何かが行われる前に、安全な時点でクエリセットが変更されます。私のコードでは、ここで .select_related() も実行しています。これにより、大きなモデルフォームセットが大幅に高速化されます!

于 2015-06-17T18:49:11.570 に答える
3

rantanplan のコメントのおかげで、解決策が見つかりました。クエリセットがどうなるかわからないため、上記のリンクで説明されている方法を使用できませんでした (これは、フォームセットがネストされた複雑なフォームです)。

とにかく、Django の BaseInlineFormSet クラスの get_queryset メソッドをオーバーライドすることで解決策を見つけました。googler が役立つ場合に備えて、mod を含めて以下にコピーしました。

def get_queryset(self):
    '''
    Copied this method from Django code and modified the ordering statement
    '''
    if not hasattr(self, '_queryset'):
        if self.queryset is not None:
            qs = self.queryset
        else:
            qs = self.model._default_manager.get_query_set()

        # If the queryset isn't already ordered we need to add an
        # artificial ordering here to make sure that all formsets
        # constructed from this queryset have the same form order.
        if not qs.ordered:
# MY MOD IS HERE:
#            qs = qs.order_by(self.model._meta.pk.name)
            qs = qs.order_by('order_index')
#/MOD

        # Removed queryset limiting here. As per discussion re: #13023
        # on django-dev, max_num should not prevent existing
        # related objects/inlines from being displayed.
        self._queryset = qs
    return self._queryset
于 2012-11-16T03:04:28.880 に答える