Djangoテンプレートで関連アイテムを並べ替える


87

DJangoテンプレートで関連アイテムのセットを並べ替えることは可能ですか?

つまり、このコード(わかりやすくするためにHTMLタグは省略されています):

{% for event in eventsCollection %}
   {{ event.location }}
   {% for attendee in event.attendee_set.all %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}

私が欲しいとほぼ正確に表示します。変更したいのは、姓でソートする出席者のリストだけです。私はこのようなことを言ってみました:

{% for event in events %}
   {{ event.location }}
   {% for attendee in event.attendee_set.order_by__last_name %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}

残念ながら、上記の構文は機能せず(空のリストが生成されます)、私が考えた他のバリエーションも機能しません(多くの構文エラーが報告されていますが、喜びはありません)。

もちろん、私の見解では、ソートされた出席者リストのある種の配列を作成することもできますが、それは醜くて壊れやすい(そして醜いことに言及しました)解決策です。

言うまでもありませんが、とにかく言いますが、私はオンラインドキュメントを熟読し、Stack Overflowとdjango-userのアーカイブを検索しましたが、何も役に立ちませんでした(ああ、クエリセットだけが辞書である場合はdictsortが実行します仕事ですが、そうではなく、そうではありません)

==============================================

Tawmasの回答を受け入れた後、追加の考えを追加するために編集されました。


Tawmasは、私が提示したとおりに問題に対処しましたが、解決策は私が期待したものではありませんでした。その結果、他の状況でも使用できる便利なテクニックを学びました。

トムの答えは、私がすでにOPで言及したアプローチを提案し、「醜い」として暫定的に拒否しました。

「醜い」は腸の反応だったので、何が悪いのかを明らかにしたかった。そうすることで、それが醜いアプローチである理由は、レンダリングするテンプレートにクエリセットを渡すというアイデアに夢中になっているためだと気づきました。その要件を緩和すると、うまくいくはずの醜いアプローチがあります。

私はまだこれを試してみましたが、むしろ、クエリセットを渡すよりも、ビューのコードは、イベントのリストを生成するクエリセットを繰り返しているとし、それに対応する参加者のためのクエリセットで各イベントを飾っていないWAS、(ソートまたはフィルタまたは何でも)望ましい方法で。そのようなもの:

eventCollection = []   
events = Event.object.[filtered and sorted to taste]
for event in events:
   event.attendee_list = event.attendee_set.[filtered and sorted to taste]
   eventCollection.append(event)

これで、テンプレートは次のようになります。

{% for event in events %}
   {{ event.location }}
   {% for attendee in event.attendee_list %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}

欠点は、ビューがすべてのイベントを一度に「実際化」する必要があることです。これは、多数のイベントがあった場合に問題になる可能性があります。もちろん、ページ付けを追加することもできますが、それはビューをかなり複雑にします。

利点は、「表示するデータを準備する」コードがそれが属するビューにあり、テンプレートが表示用にビューによって提供されるデータのフォーマットに集中できるようにすることです。これは正しく適切です。

ですから、私の計画では、大きなテーブルにはTawmasの手法を使用し、小さなテーブルには上記の手法を使用し、大小の定義は読者に任せます(笑)。

回答:


135

このように、出席者モデルで順序を指定する必要があります。例(モデルクラスの名前がAttendeeであると仮定):

class Attendee(models.Model):
    class Meta:
        ordering = ['last_name']

詳細については、マニュアルを参照してください。

編集。別の解決策は、テンプレートからアクセスできるプロパティをイベントモデルに追加することです。

class Event(models.Model):
# ...
@property
def sorted_attendee_set(self):
    return self.attendee_set.order_by('last_name')

必要に応じて、これらをさらに定義できます...


コメントありがとうございますが、これは、表示注文を出席者の永続的な所有物にしたい場合にのみ機能しますが、私はそうしません。たとえば、登録を受け取った日付で並べ替えた出席者を表示したい場合は、どの出席者に空きがないことを通知する必要があるかを知ります。
デイルウィルソン

私はあなたのために別の解決策を追加しました。それはあなたが必要とする柔軟性を可能にするはずです。
tawmas 2011年

@Mark確かにそうです。私の知る限り理解して@property関与なしゲッターやセッターがありませんよう、ここで過剰です:stackoverflow.com/questions/1554546/...
リックWestera

テンプレートに厳密に必要というわけではありませんが、ここの@propertyを使用すると、アプリケーションコードからのアクセスがよりクリーンになりますが、パフォーマンスがわずかに低下します(ラップトップでは<30 ns)。もちろんこれはスタイルの問題であり、非常に主観的です。
tawmas 2014年

2つの属性に関してセットをソートする場合、これは次のコマンドです
。classMeta

135

テンプレートフィルターdictsort を使用できますhttps://docs.djangoproject.com/en/dev/ref/templates/builtins/#std:templatefilter-dictsort

これは機能するはずです:

{% for event in eventsCollection %}
   {{ event.location }}
   {% for attendee in event.attendee_set.all|dictsort:"last_name" %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}

22
すごい !そして、疑問に思う人のために、また、そこにあるdictsortreverseddocs.djangoproject.com/en/dev/ref/templates/builtins/...
ミカエル

1
私の元の投稿から引用すると、ああ、クエリセットだけが辞書だった場合、dictsortがその仕事をしますが、そうではなく、そうではありません。
デイルウィルソン

これは実際には少なくする必要があると思います。レコードをフェッチする前に、モデルに並べ替えを処理させます。
acpmasquerade 2015

1
@DaleWilson、私は実際にdictsortあなたとほぼ同じようにコードを適切に処理しています。興味深いことに、クエリセットでは正常に機能しているようです。
mlissner 2015

2
さらに明確にするために、スペースは重要です。 {% for attendee in event.attendee_set.all|dictsort:"last_name" %}出席者{% for attendee in event.attendee_set.all | dictsort:"last_name" %}を並べ替えますが、forループの出力を並べ替えようとし、を中断しforます。
mattsl 2018年

3

1つの解決策は、カスタムテンプレートを作成することです。

@register.filter
def order_by(queryset, args):
    args = [x.strip() for x in args.split(',')]
    return queryset.order_by(*args)

このように使用します:

{% for image in instance.folder.files|order_by:"original_filename" %}
   ...
{% endfor %}

0

再グループ化はあなたが望むことを行うことができるはずですが、ビューに戻ってあなたが望むようにそれらを注文できない理由はありますか?


ビューでそれらを並べ替えるには、イベントを繰り返し処理し、イベントごとに、そのイベントに関連するある種の参加者のコンテナーを適切に並べ替えられた順序で作成し、コンテナーのコレクション全体を次の形式でテンプレートに渡す必要があります。テンプレートが参加者の適切なコレクションを見つける聞かせそれがイベントを通じて反復。私が言ったように、それは可能でしたが、それは良い解決策ではありません。ビューとテンプレートの間の結合、並列反復などが多すぎます。一般的な問題となるはずの問題に対するより良い解決策を望んでいました。
デイルウィルソン

再グループ化を確認しましたが、希望どおりに機能していないようです。特にドキュメントには次のように書かれています。[quote] {%regroup%}は入力を順序付けしないことに注意してください!この例は、最初に人のリストが性別で並べられているという事実に依存しています。[endquote]
Dale Wilson
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.