[英]icontains and getlist django python
我们正在尝试返回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
,并且每个项应该是可迭代的(例如列表)。 然后它将执行或列表的项目之间的编辑逻辑,并与不同的键之间编辑逻辑。 如果iterable为空,则忽略它。
所以我们可以把支票写成:
unroll_lists_or(queryset, news_title__icontains=title, news_source=source)
如果title
包含两个项目(所以title == [title1, title2]
),并且source
包含三个项目(so 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)
我能够通过在get_querset()
函数中创建2个单独的函数来解决这个问题,该函数在发出GET请求时被调用。
def get_queryset(self):
queryset = News.objects.all()
source_list = self.request.query_params.getlist('source')
keyword_list = self.request.query_params.getlist('title')
if source_list or keyword_list:
def create_q_source(*args):
list = [*args]
source = Q()
for value in list:
source.add(Q(news_source=value), Q.OR)
return source
def create_q_keyword(*args):
list = [*args]
keyword = Q()
for value in list:
keyword.add(Q(news_title__icontains=value), Q.OR)
return keyword
queryset = queryset.filter(create_q_source(*source_list),create_q_keyword(*keyword_list))
return queryset
编辑:当您转到api链接并传入参数时,将根据传入的内容进行过滤:
http://127.0.0.1:8000/api/notes/?keyword=trump&keyword=beyond&keyword=money&source=1
SQL等价物:
select * from news where news_source = 1 AND news_title like '%beyond%' OR news_title like '%money%'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.