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

时间:2022-08-29 20:22:48

Is it possible to sort a set of related items in a DJango template?

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

That is: this code (with HTML tags omitted for clarity):

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

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

displays almost exactly want I want. The only thing I want to change is I the list of attendees to be sorted by last name. I've tried saying something like this:

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

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

Alas, the above syntax doesn't work (it produces an empty list) and neither does any other variation I have thought of (lot's of syntax errors reported, but no joy).

唉,上面的语法不起作用(它生成一个空列表),我也没有想到任何其他变体(报告了很多语法错误,但没有乐趣)。

I could, of course, produce some kind of array of sorted attendee lists in my view, but that is an ugly and fragile (and did I mention ugly) solution.

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

Needless to say, but I'll say it anyway, I have perused the on-line docs and searched Stack Overflow and the archives of django-user without finding anything helpful (ah, if only a query set were a dictionary dictsort would do the job, but it's not and it doesn't)

毫无疑问,但我还是要说,我已经仔细研究了在线文档,搜索了堆栈溢出和django用户的存档,但没有发现任何有用的东西(啊,如果查询集是字典dictsort就可以做到这一点,但它不是,它也不是)

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

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

Edited to add additional thoughts after accepting Tawmas's answer.

在接受了陶玛斯的回答后,编辑添加了更多的想法。


Tawmas addressed the issue exactly as I presented it -- although the solution was not what I expected. As a result I learned a useful technique that can be used in other situations as well.

Tawmas按照我的描述解决了这个问题——尽管解决方案并不是我期望的那样。结果我学到了一种有用的技巧,这种技巧也可以在其他情况下使用。

Tom's answer proposed an approach I had already mentioned in my OP and tentatively rejected as being "ugly".

汤姆的回答提出了一种方法,我已经在我的计划中提到过,但暂时被拒绝为“丑陋”。

The "ugly" was a gut reaction, and I wanted to clarify what was wrong with it. In doing so I realized that the reason it was an ugly approach was because I was hung up on the idea of passing a query set to the template to be rendered. If I relax that requirement, there is an un-ugly approach that should work.

“丑陋”是一种本能的反应,我想澄清它有什么问题。在这样做的过程中,我意识到它之所以是一种糟糕的方法,是因为我被一种想法所困扰,即将查询集传递给要呈现的模板。如果我放宽这一要求,有一种不丑陋的方法应该行得通。

I haven't tried this yet, but suppose that rather than passing the queryset, the view code iterated through the query set producing a list of Events, then decorated each Event with a query set for the corresponding attendees which WAS sorted (or filtered, or whatever) in the desired way. Something like so:

我还没有尝试过这一点,但是假设不是通过queryset,而是遍历查询集生成事件列表,然后对每个事件进行修饰,然后为相应的参与者设置一个查询集,这些参与者按照所期望的方式进行排序(或过滤,或其他)。类似这样:

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)

Now the template becomes:

现在,模板就变成:

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

The downside is the view has to "actualize" all of the events at once which could be a problem if there were large numbers of events. Of course one could add pagination, but that complicates the view considerably.

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

The upside is the "prepare the data to be displayed" code is in the view where it belongs letting the template focus on formatting the data provided by the view for display. This is right and proper.

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

So my plan is to use Tawmas' technique for large tables and the above technique for small tables, with the definition of large and small left to the reader (grin.)

因此,我的计划是使用Tawmas的技术来处理大表,以及上面的技术来处理小表,让读者来定义大表和小表(grin)。

3 个解决方案

#1


94  

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

您需要在参与者模型中指定顺序,如下所示。例如(假设您的模型类被命名为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...

你可以根据你的需要来定义更多的这些。

#2


76  

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

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

#3


0  

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?

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

#1


94  

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

您需要在参与者模型中指定顺序,如下所示。例如(假设您的模型类被命名为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...

你可以根据你的需要来定义更多的这些。

#2


76  

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

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

#3


0  

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?

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