我试图建立一个我正在建立的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_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'))
要求:Django==2.0.2,Django querysetsequence==0.8
如果您希望组合查询集,但仍然使用QuerySet,则可能需要检查django查询集序列。
但需要注意的是,它只需要两个查询集作为参数。但使用python-reduce,您可以始终将其应用于多个查询集。
from functools import reduce
from queryset_sequence import QuerySetSequence
combined_queryset = reduce(QuerySetSequence, list_of_queryset)
下面是我遇到的一个情况,以及我如何使用列表理解、reduce和django查询集序列
from functools import reduce
from django.shortcuts import render
from queryset_sequence import QuerySetSequence
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
mentor = models.ForeignKey('self', null=True, on_delete=models.SET_NULL, related_name='my_mentees')
class Book(models.Model):
name = models.CharField(max_length=20)
owner = models.ForeignKey(Student, on_delete=models.CASCADE)
# as a mentor, I want to see all the books owned by all my mentees in one view.
def mentee_books(request):
template = "my_mentee_books.html"
mentor = People.objects.get(user=request.user)
my_mentees = mentor.my_mentees.all() # returns QuerySet of all my mentees
mentee_books = reduce(QuerySetSequence, [each.book_set.all() for each in my_mentees])
return render(request, template, {'mentee_books' : mentee_books})