在 Django 模板中对相关项进行排序

是否可以在 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 的存档,没有找到任何有用的东西(啊,如果查询集是字典独裁排序就好了,但它不是,也不是)

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

编辑以添加其他想法 在接受了塔马斯的回答之后。


塔马斯完全按照我提出的方式处理了这个问题——尽管解决办法不是我所期望的。因此,我学到了一个有用的技术,也可以在其他情况下使用。

汤姆的回答提出了一种我在我的 OP 中已经提到过的方法,并且试探性地以“丑陋”为由拒绝了它。

“丑陋”是一种本能反应,我想弄清楚它到底出了什么问题。在这样做的过程中,我意识到这是一个丑陋的方法的原因是因为我被传递一个查询集到要呈现的模板的想法所困扰。如果我放宽这个要求,就会有一个不难看的方法可行。

我还没有尝试过这种方法,但是假设视图代码不是传递查询集,而是遍历查询集,生成一个 Events 列表,然后用一个查询集为相应的参与者修饰每个 Event,曾经是按照所需的方式对这些参与者进行排序(或者过滤,或者其他任何方式)。大概是这样的:

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 %}

缺点是视图必须一次“实现”所有事件,如果有大量事件,这可能是一个问题。当然可以添加分页,但这会使视图变得相当复杂。

优点是“准备要显示的数据”代码位于它所属的视图中,让模板专注于格式化视图提供的用于显示的数据。这是正确的和适当的。

因此,我的计划是使用塔瓦马斯的技术为大表和上述技术为小 表,大和小的定义留给读者(咧嘴一笑。)

83001 次浏览

You need to specify the ordering in the attendee model, like this. For example (assuming your model class is named Attendee):

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

See the manual for further reference.

EDIT. Another solution is to add a property to your Event model, that you can access from your template:

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

You could define more of these as you need them...

regroup should be able to do what you want, but is there a reason you can't order them the way you want back in the view?

You can use template filter dictsort https://docs.djangoproject.com/en/dev/ref/templates/builtins/#std:templatefilter-dictsort

This should work:

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

One solution is to make a custom templatag:

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

use like this:

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