小编典典

如何在 Django 视图中组合两个或多个查询集?

all

我正在尝试为我正在构建的 Django 站点构建搜索,并且在该搜索中,我正在搜索三种不同的模型。为了对搜索结果列表进行分页,我想使用通用的
object_list 视图来显示结果。但要做到这一点,我必须将三个查询集合并为一个。

我怎样才能做到这一点?我试过这个:

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_listarticle_listpost_list


阅读 163

收藏
2022-03-02

共1个答案

小编典典

将查询集连接成一个列表是最简单的方法。如果无论如何都会为所有查询集命中数据库(例如,因为需要对结果进行排序),这不会增加进一步的成本。

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 或更高版本,则可以使用attrgetterlambda
代替。我记得读过它更快,但我没有看到一百万个项目列表的明显速度差异。

from operator import attrgetter
result_list = sorted(
    chain(page_list, article_list, post_list),
    key=attrgetter('date_created'))
2022-03-02