【问题标题】: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(..)

标签: python django django-templates django-views django-orm


【解决方案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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-22
    • 2012-09-30
    • 2020-08-18
    • 2021-11-26
    • 2020-08-16
    • 1970-01-01
    • 2019-08-14
    • 1970-01-01
    相关资源
    最近更新 更多