【问题标题】:Sorting related items in a Django template在 Django 模板中对相关项目进行排序
【发布时间】:2011-09-26 06:29:31
【问题描述】:

是否可以在 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 完全按照我提出的方式解决了这个问题——尽管解决方案不是我所期望的。结果,我学到了一种有用的技术,也可以在其他情况下使用。

Tom 的回答提出了一种我已经在我的 OP 中提到的方法,并暂时拒绝为“丑陋”。

“丑”是一种本能反应,我想澄清一下它有什么问题。在这样做的过程中,我意识到这是一个丑陋的方法的原因是因为我对将查询集传递给要呈现的模板的想法很感兴趣。如果我放宽该要求,则应该有一种不丑陋的方法。

我还没有尝试过,但是假设视图代码不是传递查询集,而是通过查询集迭代生成事件列表,然后用相应参与者的查询集装饰每个事件,以所需的方式排序(或过滤,或其他)。像这样:

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 的技术,对小表使用上述技术 表格,大小的定义留给读者(笑)

【问题讨论】:

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


    【解决方案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 %}
    

    【讨论】:

    • 这可行,但重复对数据库的查询
    【解决方案2】:

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

    【讨论】:

    • 太棒了!对于那些想知道的人,还有dictsortreverseddocs.djangoproject.com/en/dev/ref/templates/builtins/…
    • 引用我原来的帖子:啊,如果只有一个查询集是一个字典 dictsort 就可以完成这项工作,但事实并非如此。
    • 我认为这在实践中应该少一些,让模型在获取记录之前处理排序。
    • @DaleWilson,我实际上已经让dictsort 在几乎和你一样的代码上正常工作。有趣的是,它似乎在查询集上运行良好。
    • 为了更清楚起见,空格很重要:{% for attendee in event.attendee_set.all|dictsort:"last_name" %} 对与会者进行排序,但 {% for attendee in event.attendee_set.all | dictsort:"last_name" %} 尝试对 for 循环的输出进行排序并破坏 for
    【解决方案3】:

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

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

    请参阅the manual 以获取更多参考。

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

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

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

    【讨论】:

    • 感谢您的评论,但这仅在我想将显示顺序设为与会者的永久财产时才有效,而我不这样做。例如,我可能希望显示按收到注册日期排序的与会者,这样我就知道应该通知哪些与会者没有空间了。
    • 我为您添加了替代解决方案。它应该为您提供所需的灵活性。
    • @Mark 确实如此。据我了解@property 在这里过于矫枉过正,因为没有涉及到 getter 或 setter:stackoverflow.com/questions/1554546/…
    • 虽然模板不是严格需要的,但我发现这里的@property 可以从应用程序代码进行更清晰的访问,尽管会涉及到小的性能损失(
    • 如果你想根据两个属性对集合进行排序,命令如下:class Meta: ordering = ['last_name', 'first_name']
    【解决方案4】:

    regroup 应该能够做你想做的事,但是你有什么理由不能在视图中以你想要的方式订购它们?

    【讨论】:

    • 要在视图中对它们进行排序,我需要遍历事件并为每个事件创建一个容器,其中包含与该事件相关的某种参与者以正确排序的顺序,然后传递整个集合将容器添加到模板中,让模板在 it 遍历事件时找到适当的参与者集合。正如我所说,它可以完成,但这不是一个好的解决方案。它需要视图和模板之间过多的耦合、并行迭代等。我希望能找到更好的解决方案来解决应该是常见问题的问题。
    • 我查看了 regroup,但它似乎没有达到我想要的效果。特别是文档说: [quote] 请注意 {% regroup %} 不会对其输入进行排序!我们的示例依赖于人员列表首先按性别排序的事实。 [结束引用]
    猜你喜欢
    • 2018-02-04
    • 2015-09-10
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 2018-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多