如何在 Django 视图中组合两个或多个查询集? [英] How can I combine two or more querysets in a Django view?

查看:56
本文介绍了如何在 Django 视图中组合两个或多个查询集?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to build the search for a Django site I am building, and in that search, I am searching in three different models. And to get pagination on the search result list, I would like to use a generic object_list view to display the results. But to do that, I have to merge three querysets into one.

我该怎么做?我试过这个:

How can I do that? I've tried this:

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")

但这行不通.当我尝试在通用视图中使用该列表时出现错误.该列表缺少克隆属性.

But this doesn't work. I get an error when I try to use that list in the generic view. The list is missing the clone attribute.

如何合并page_listarticle_listpost_list 三个列表?

How can I merge the three lists, page_list, article_list and post_list?

推荐答案

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

Concatenating the querysets into a list is the simplest approach. If the database will be hit for all querysets anyway (e.g. because the result needs to be sorted), this won't add further cost.

from itertools import chain
result_list = list(chain(page_list, article_list, post_list))

使用 itertools.chain 比循环每个列表并一个一个附加元素要快,因为 itertools 是用 C 实现的.它还比转换每个查询集消耗更少的内存在连接之前放入一个列表.

Using itertools.chain is faster than looping each list and appending elements one by one, since itertools is implemented in C. It also consumes less memory than converting each queryset into a list before concatenating.

现在可以对结果列表进行排序,例如按日期(根据 hasen j 对另一个答案的评论中的要求).sorted() 函数方便地接受一个生成器并返回一个列表:

Now it's possible to sort the resulting list e.g. by date (as requested in hasen j's comment to another answer). The sorted() function conveniently accepts a generator and returns a list:

result_list = sorted(
    chain(page_list, article_list, post_list),
    key=lambda instance: instance.date_created)

如果您使用的是 Python 2.4 或更高版本,则可以使用 attrgetter 而不是 lambda.我记得读到它更快,但我没有看到一百万个项目列表的明显速度差异.

If you're using Python 2.4 or later, you can use attrgetter instead of a lambda. I remember reading about it being faster, but I didn't see a noticeable speed difference for a million item list.

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

这篇关于如何在 Django 视图中组合两个或多个查询集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆