[英]icontains and getlist django python
We are trying to return a list of titles for the Django API, in which the title can have a few keywords. 我们正在尝试返回Django API的标题列表,其中标题可以包含几个关键字。
So for instance, if we use the __icontains
method to search for "money" and "world" ( api.com/?keyworld=money&keyword=world
) this will return all records that contain money, world or both. 因此,例如,如果我们使用
__icontains
方法搜索“money”和“world”( api.com/?keyworld=money&keyword=world
),这将返回包含money,world或两者的所有记录。
The related SQL statement is: 相关的SQL语句是:
select * from news
where news_source = 1 or news_source = 2
and news_title like '%money%' or news_title like '%world%'
We are trying to use this code to allow the user to have multiple keywords for the __icontains
as well as multiple sources, so the end goal is: 我们正在尝试使用此代码来允许用户为
__icontains
以及多个源提供多个关键字,因此最终目标是:
api.com/?keyworld=money&keyword=world&source=1&source=2
Our code: 我们的代码:
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
The issue is that this is only returning the second keyword if a second keyword is used, and not other keywords prior to what is typed in &keyword=
. 问题是,如果使用第二个关键字,则仅返回第二个关键字,而不是在
&keyword=
键入的关键字之前返回其他关键字。
You can not perform an __icontains
with a list, but you can for example design a function that, for a list constructs the logical or of these values. 您不能使用列表执行
__icontains
,但是您可以设计一个函数,对于列表构造逻辑或这些值。 For example: 例如:
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()
])
You can then call the unroll_lists_or
with a queryset, and each item should be an iterable (for example a list). 然后,您可以使用查询集调用
unroll_lists_or
,并且每个项应该是可迭代的(例如列表)。 It will then perform or -logic between the items of the list, and and -logic between different keys. 然后它将执行或列表的项目之间的编辑逻辑,并与不同的键之间编辑逻辑。 In case an iterable is empty, it is ignored.
如果iterable为空,则忽略它。
So we can then write the check as: 所以我们可以把支票写成:
unroll_lists_or(queryset,
news_title__icontains=title, news_source=source)
In case title
contains two items (so title == [title1, title2]
), and source
contains three items (so source = [source1, source2, source3]
), then this will result in: 如果
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)
)
You can however combine it with an .filter(..)
for the __in
check. 但是,您可以将它与
.filter(..)
用于__in
检查。 For example: 例如:
queryset = News.objects.all()
if source:
queryset = queryset.filter(news_source__in=source)
queryset = unroll_lists_or(queryset, news_title__icontains=title)
I was able to solve this by creating 2 separate functions within the get_querset()
function, which is called when a GET request is made. 我能够通过在
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
Edit: When you go to the api link and pass in the parameters, filtering will occur based on what is passed in: 编辑:当您转到api链接并传入参数时,将根据传入的内容进行过滤:
http://127.0.0.1:8000/api/notes/?keyword=trump&keyword=beyond&keyword=money&source=1
SQL Equivalent: 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.