按添加的字段对查询集进行排序

Sort queryset by added field

我正在尝试向我的查询集实例添加一个额外字段,然后按新字段对集合进行排序。 但是我得到一个字段错误(Cannot resolve keyword 'foo' into field. Choices are: ...

我的观点(摘要):

def view(request):
    instances = Model.objects.all()
    for counter, instance in enumerate(instances):
        instance.foo = 'bar' + str(counter)
    instances.order_by('foo')  #this line causes trouble
    return render(request, 'template.html', {'instances': instance})

我的模板:

{% for instance in instances %}
    {{instance.foo}}
{% endfor %}

如果我省略 order_by 行,模板会按预期呈现,因此该字段似乎就在那里。

为什么我会收到字段错误?
如果有人能帮助我理解我做错了什么,那就太好了。

提前致谢。


我找到了将模板更改为

的可能解决方案

{% for instance in instances|dictsort:'foo' %}

这很好用,但据我所知,视图中的逻辑应该尽可能少,所以我认为排序应该在视图中完成。
或者这实际上是正确的方法吗?

Django ORM 旨在构造数据库 查询。因此,您只能查询 数据库 "knows"。您自己添加的方法、特性或属性对于数据库是未知的。 .order_by 因此没有效果,因为你 "patched" instances 查询集中的对象。

但是,如果您调用 instances.order_by,您将构建一个 new 查询集。此查询集采用父级的上下文,因此表示(略微)修改的 查询 ,但同样是一个查询。旧查询集是否已经过评估或修补并不重要。

此外,即使有列 foo,也无济于事,因为 instance.order_by instance 查询集进行排序, 它构造了一个新的,除了行是有序的之外,它看起来与旧的大致相同。

因此您现在必须在 Python 中进行排序。例如,您可以使用 sorted(..) 构造一个 有序 元素的列表,例如:

from operator import <b>attrgetter</b>

def view(request):
    instances = Model.objects.all()
    for counter, instance in enumerate(instances):
        instance.foo = 'bar' + str(counter)
    <b>mydata = sorted(instances, key=attrgetter('foo'))</b>
    return render(request, 'template.html', {'instances': <b>mydata</b>})

所以现在 mydata 不再是 QuerySet,而是 vanilla list。此外请注意,数据库中的排序可能 与 Python 中的排序略有 不同。在 Python 中,如果并非所有元素都具有相同的类型,则可能会发生异常,而且不能保证顺序关系背后的语义完全相同。

Python 对象中的新属性不存在于数据库中,仅存在于那些实例中。 order_by 更改查询集,而不是您当前存储在内存中的对象列表。

一种方法是在视图中使用内置 python 排序函数,例如:sorted 甚至 list.sort().