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

Posted

技术标签:

【中文标题】按添加的字段对查询集进行排序【英文标题】:Sort queryset by added field 【发布时间】:2019-01-13 13:15:26 【问题描述】:

我正在尝试向我的查询集的实例添加一个额外的字段,然后按新字段对集合进行排序。 但我得到一个字段错误(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' %

效果很好,但据我了解,视图中的逻辑应该尽可能少,所以我认为应该在视图中进行排序。 或者这实际上是正确的方法?

【问题讨论】:

因为它不是一个字段,所以您为对象添加了一个额外的属性。但这没关系。查询集首先处理查询。如果您调用.order_by,您将在该模型上构造一个新的QuerySet。由于foo 不是字段,因此无法对此进行排序。 感谢您的回答,这澄清了很多。所以order_by 实际上会导致对数据库的另一个调用,当然该字段不存在,所以我得到了错误。我将如何按新属性排序? - 编辑:刚刚看到你的答案,这就解释了。 带有 Python 排序功能,例如 sorted(..) 【参考方案1】:

Django ORM 旨在构建数据库 查询。因此,您只能查询数据库“知道”的内容。您自己添加的方法、属性或属性对数据库是未知的。 .order_by 因此无效,因为您“修补”了 instances 查询集中的对象。

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

此外,即使有一个列 foo,它也无济于事,因为 instance.order_by 确实订购了 instance 查询集,它构造了一个新的查询集,看起来大约和旧的一样,只是行是有序的。

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

from operator import attrgetter

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

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

【讨论】:

这行得通,谢谢。我现在已经在我的代码中到处实现了,但是当我尝试对 ManyToMany 表单字段的选项进行排序时,我得到一个属性错误('list' object has no attribute 'all')。我尝试使用 form.fields['instances'].querset=mydata 限制选择。您知道如何实现这一目标吗? @HahaMuntz:如果需要查询集,则不能这样做。那么你可能最好在数据库中添加一个额外的foo 字段,并使用计算定期更新它。【参考方案2】:

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

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

【讨论】:

以上是关于按添加的字段对查询集进行排序的主要内容,如果未能解决你的问题,请参考以下文章

es 搜索排序

怎么用sql对搜索结果排序并添加序号

Access 2010 SQL--在交叉表查询中按聚合函数对行进行排序

mysql 查询时 按照某个字段计算后的值 排序?

按 ACF 日期对帖子进行排序并为每个月添加标题

mysql 对符合条件的字段进行排序