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

时间:2011-06-30 19:25:40

标签: python django django-templates sql-order-by

是否可以在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会做的工作,但它不是,它不会)

============================================== < / p>

编辑添加其他想法 在接受了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的技术用于大型表格,将上述技术用于小型表格 表格,大小的定义留给读者(咧嘴笑)。

4 个答案:

答案 0 :(得分:113)

您需要在与会者模型中指定排序,如下所示。例如(假设您的模型类名为Attendee):

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

有关详细信息,请参阅the manual

修改即可。另一种解决方案是向您的事件模型添加一个属性,您可以从模板中访问该属性:

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

您可以根据需要定义更多这些......

答案 1 :(得分:94)

您可以使用模板过滤器 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 %}

答案 2 :(得分: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 %}

答案 3 :(得分:0)

regroup应该能够做你想做的事,但有没有理由你不能按照你想要的方式订购它们?