我们正在尝试为 Django API 返回一个标题列表,其中标题可以有几个关键字。
例如,如果我们使用 __icontains
方法搜索“money”和“world”( api.com/?keyworld=money&keyword=world
),这将返回包含money、world 或两者的所有记录。
相关的SQL语句是:
select * from news
where news_source = 1 or news_source = 2
and news_title like '%money%' or news_title like '%world%'
我们正在尝试使用此代码来允许用户为
__icontains
以及多个来源拥有多个关键字,因此最终目标是:api.com/?keyworld=money&keyword=world&source=1&source=2
我们的代码:
def get_queryset(self):
queryset = News.objects.all()
title = self.request.query_params.getlist('title')
source = self.request.query_params.getlist('source')
if title:
queryset = queryset.filter(news_title__icontains=title, news_source__in=source)
return queryset
问题是这仅在使用第二个关键字时返回第二个关键字,而不是在
&keyword=
中键入的内容之前的其他关键字。 最佳答案
您不能使用列表执行 __icontains
,但您可以例如设计一个函数,为列表构造这些值的逻辑或。例如:
from django.db.models import Q
from functools import reduce
from operator import or_
def or_fold(list_of_qs):
if list_of_qs:
return reduce(or_, list_of_qs)
else:
return Q()
def unroll_lists_or(qs, **kwargs):
return qs.filter([
or_fold(Q(**{k: vi}) for vi in v)
for k, v in kwargs.items()
])
然后,您可以使用查询集调用
unroll_lists_or
,并且每个项目都应该是可迭代的(例如列表)。然后它将执行列表项之间的 or 逻辑,以及不同键之间的 and 逻辑。如果可迭代对象为空,则将其忽略。所以我们可以把支票写成:
unroll_lists_or(queryset, news_title__icontains=title, news_source=source)
如果
title
包含两个项目(所以 title == [title1, title2]
),并且 source
包含三个项目(所以 source = [source1, source2, source3]
),那么这将导致:qs.filter(
Q(news_title__icontains=title1) | Q(news_title__icontains=title2),
Q(news_source=source1) | Q(news_source=source2) | Q(news_source=source3)
)
但是,您可以将它与
.filter(..)
结合起来进行 __in
检查。例如:queryset = News.objects.all()
if source:
queryset = queryset.filter(news_source__in=source)
queryset = unroll_lists_or(queryset, news_title__icontains=title)
关于python - icontains 和 getlist django python,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51031397/