我正在尝试搜索要构建的 Django 网站,在该搜索中,我正在搜索 3 种不同的模型。为了在搜索结果列表上进行分页,我想使用一个通用的 object_list 视图来显示结果。但是要做到这一点,我必须将 3 个查询集合并为一个。
我怎样才能做到这一点?我已经试过了:
result_list = []
page_list = Page.objects.filter(
Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term))
article_list = Article.objects.filter(
Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term) |
Q(tags__icontains=cleaned_search_term))
post_list = Post.objects.filter(
Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term) |
Q(tags__icontains=cleaned_search_term))
for x in page_list:
result_list.append(x)
for x in article_list:
result_list.append(x)
for x in post_list:
result_list.append(x)
return object_list(
request,
queryset=result_list,
template_object_name='result',
paginate_by=10,
extra_context={
'search_term': search_term},
template_name="search/result_list.html")
但这是行不通的。当我尝试在通用视图中使用该列表时出现错误。该列表缺少克隆属性。
有人知道我如何合并三个列表page_list
, article_list
和post_list
吗?
将查询集连接到列表是最简单的方法。如果无论如何将对所有查询集命中数据库(例如,由于需要对结果进行排序),则不会增加成本。
from itertools import chain
result_list = list(chain(page_list, article_list, post_list))
使用itertools.chain
比循环遍历每个列表和一个接一个地添加元素要快,这itertools
是用 C 实现的。与串联之前将每个查询集转换成列表相比,它消耗的内存更少。
现在可以对结果列表进行排序,例如按日期排序(按照 hasen j 对另一个答案的评论中的要求)。 sorted()
函数方便地接受生成器并返回一个列表:
result_list = sorted(
chain(page_list, article_list, post_list),
key=lambda instance: instance.date_created)
如果您使用的是 Python 2.4 或更高版本,则可以使用attrgetter
而不是 lambda。我记得曾经读过关于它更快的文章,但是对于一百万个物品清单,我没有看到明显的速度差异。
from operator import attrgetter
result_list = sorted(
chain(page_list, article_list, post_list),
key=attrgetter('date_created'))
试试这个:
matches = pages | articles | posts
它保留了查询集的所有功能,如果您想使用order_by
或类似的功能,那就很好了。
请注意:这不适用于来自两个不同模型的查询集。
相关的,为了混合来自相同模型的查询集,或用于来自几个模型的相似字段,从Django 1.11开始,还可以使用QuerySet.union()
方法:
union()
union(*other_qs, all=False)
Django 1.11 的新功能。使用 SQL 的 UNION 运算符组合两个或多个 QuerySet 的结果。例如:
>>> qs1.union(qs2, qs3)
默认情况下,UNION 运算符仅选择不同的值。要允许重复值,请使用 all = True 参数。
union(),intersection()和 difference()返回第一个 QuerySet 类型的模型实例,即使参数是其他模型的 QuerySet 也是如此。只要所有 QuerySet 中的 SELECT 列表相同(至少类型,名称与类型顺序相同的名称),传递不同的模型即可。
另外,在结果 QuerySet 上仅允许 LIMIT,OFFSET 和 ORDER BY(即 slicing 和 order_by())。此外,数据库对组合查询中允许的操作设置了限制。例如,大多数数据库在组合查询中不允许 LIMIT 或 OFFSET。