按添加的字段对查询集进行排序
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()
。
【讨论】:
以上是关于按添加的字段对查询集进行排序的主要内容,如果未能解决你的问题,请参考以下文章