Django模板切片 - 逆转顺序

时间:2009-12-14 01:50:50

标签: python django django-templates

感谢我学到的另一个问题的非常有用的提示,我可以通过在模板中切片来限制列表中的值:

{% for comment in thread.comment_set.all|slice:":3" %}

现在我想得到我评论的最后3个结果,所以我认为一个简单的“:-3”或“-3”就可以了,唉:

Caught an exception while rendering: Negative indexing is not supported.

还使用:

{% for comment in thread.comment_set.all|slice:":3" reversed %}

不行,因为如果我有5条评论,而不是1,2,3则显示3,2,1顺序中的前三条。

有没有办法在不进入我的数据库的情况下显示帖子的最后3条评论?我希望能够纯粹使用模板系统来做到这一点。

{% for comment in thread.comment_set.all|dictsortreversed:"created"|slice:"3" %}

由于我的表具有创建的时间戳,显示最后三个。

6 个答案:

答案 0 :(得分:13)

Django的数据库查询是懒惰评估的,因此thread.comment_set.all的结果是QuerySet,而不是列表。 QuerySet支持许多类似列表的函数,但不支持负片,因此索引错误不是来自模板过滤器本身。 (如果您很好奇,QuerySet对象上的切片会被转换为SQL语句中的limit子句,这就是您不能使用负数的原因。)

一般来说,Django鼓励严格的模板和模型分离; views.py模块是您进行任何需要了解数据库模型和查询集方法以将模型数据转换为模板的简单变量和结构的工作的粘合剂。

从模板中对模型运行相关查询不是您通常在Django模板中看到的,这是有充分理由的。现在,从comment_set中切割最后三个元素似乎非常简单。但请记住,数据库不会以任何保证顺序返回结果。这意味着,除了切片之外,您现在还需要添加一个order_by子句;根本没有办法在模板中表达这一点,也不应该存在。最好将视图视为模型和模板之间的转换,并让这些面向数据库的工作在那里完成,而不是嵌入HTML中。

在这种情况下,我建议您从视图中将有序切片传递给模板:

# take first three sorted descending
comments = thread.comment_set.order_by('-something')[:3]

context = Context({'comments':comments})
return HttpResponse(tmplt.render(context))

如果您必须在模板中进行切片,并且您真的不关心对结果进行排序,请将列表传递给模板。 slice过滤器很乐意进行否定切片:

comments = list(thread.comment_set.all())
context = Context('comments':comments)

在模板中:

{% for comment in comments|slice:"-3:" %}

答案 1 :(得分:10)

我还没有看到过频繁使用的dictsortreversed过滤器,根据文档,它需要按键排序

{% for comment in thread.comment_set.all|dictsortreversed:"name"|slice:"3" %}

答案 2 :(得分:1)

使用Comment类的Meta类的“ordering”属性来设置元素的所需排序。

IMO模板不适合订购数据集。订购应在模型或视图中完成。

答案 3 :(得分:1)

我认为我需要这个并制定更完整的解决方案。希望人们觉得它很有用。视图需要找到last inserted record (example here)的ID。您必须反转顺序并获取最新输入的最新记录的ID(PK),这将是第一个记录,现在很容易在堆顶部找到;-)。计算你想要的下限id值,然后在最后使用这个操作符从最低到最新或最后一个条目排序...... [n:m](我认为这只是一个列表操作符),丢弃不需要的记录,然后以正常顺序呈现它。对于django表示例,这里是我的代码:

def showLatestRels(request):
    #This view shows the latest 15 entries in the Release table
    LastInserted = Release.objects.order_by('-pk')[0]
    UpperLimit = LastInserted.id
    LowerLimit = UpperLimit - 15
    RelTable = Release.objects.all()
    tablevalslat = ReleaseTable(RelTable[LowerLimit:UpperLimit])
    RequestConfig(request).configure(tablevalslat)
    return render(request, 'DCESrtap/latrels.html', {'tablevalslat': tablevalslat}

有很多方法可以做,请参阅Django docs Make/limit Queries
但无法让dictsort的想法奏效......

答案 4 :(得分:0)

您不能在将列表传递给模板之前对其进行切片吗?

答案 5 :(得分:0)

如果已经通过“created”排序了查询集,则可以将其反转。所以这是一个更快的解决方案。

{% for comment in thread.comment_set.all.reverse|slice:":3" %}

此外,如果你不想按相反的顺序。

{% for comment in thread.comment_set.all.reverse|slice:":3"|dictsort:"created" %}

虽然您应该遵循上面的Jarrets Hardie建议并在视图中执行所有逻辑,而不是在模板中。