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

Dal*_*son 77 python django sql-order-by django-templates

是否可以在DJango模板中对一组相关项进行排序?

即:此代码(为清晰起见,省略了HTML标记):

{% for event in eventsCollection %}
   {{ event.location }}
   {% for attendee in event.attendee_set.all %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}
Run Code Online (Sandbox Code Playgroud)

显示几乎完全是我想要的.我唯一想要改变的是我按照姓氏排序的与会者名单.我试过说这样的话:

{% for event in events %}
   {{ event.location }}
   {% for attendee in event.attendee_set.order_by__last_name %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}
Run Code Online (Sandbox Code Playgroud)

唉,上面的语法不起作用(它产生一个空列表),我也没有想过任何其他变化(报告了很多语法错误,但没有快乐).

当然,我可以在我的视图中生成某种排序的与会者列表,但这是一个丑陋而脆弱的(我提到丑陋)解决方案.

毋庸置疑,但无论如何我会说,我已经仔细阅读了在线文档并搜索了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)
Run Code Online (Sandbox Code Playgroud)

现在模板变成:

{% for event in events %}
   {{ event.location }}
   {% for attendee in event.attendee_list %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}
Run Code Online (Sandbox Code Playgroud)

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

好处是"准备要显示的数据"代码在其所属的视图中,让模板专注于格式化视图提供的数据以供显示.这是正确的.

因此,我的计划是将Tawmas的技术用于大型表格,将上述技术用于小型表格,并将大小的定义留给读者(咧嘴笑).

taw*_*mas 120

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

class Attendee(models.Model):
    class Meta:
        ordering = ['last_name']
Run Code Online (Sandbox Code Playgroud)

有关详细参考,请参阅手册.

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

class Event(models.Model):
# ...
@property
def sorted_attendee_set(self):
    return self.attendee_set.order_by('last_name')
Run Code Online (Sandbox Code Playgroud)

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

  • 它在模板中没有`@ property`时也一样 (2认同)

小智 109

您可以使用模板过滤器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 %}
Run Code Online (Sandbox Code Playgroud)

  • 好极了!对于那些想知道的人,还有`dictsortreversed`:https://docs.djangoproject.com/en/dev/ref/templates/builtins/#dictsortreversed (18认同)
  • 为了进一步清楚起见,空格很重要:`{% for参加者 in event.attendee_set.all|dictsort:"last_name" %}` 对参加者进行排序,但是`{% for参加者 in event.attendee_set.all | dictsort:"last_name" %}` dictsort:"last_name" %}` 尝试对 for 循环的输出进行排序并中断 `for`。 (2认同)

小智 7

一种解决方案是制作自定义模板标签:

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

像这样使用:

{% for image in instance.folder.files|order_by:"original_filename" %}
   ...
{% endfor %}
Run Code Online (Sandbox Code Playgroud)