Django 使用'search=term1,term2'使用DRF匹配同一对象的多个标记

Django 使用'search=term1,term2'使用DRF匹配同一对象的多个标记,django,django-rest-framework,Django,Django Rest Framework,我正在将旧的Django 1.11代码库升级到Django和Django Rest框架的最新版本,但在Django Rest框架的最新版本中使用多个术语时,?search=…过滤器是如何工作的,我遇到了一道难题 在DRF版本3.6.3之前,可以执行?search=term1、term2端点请求,并使DRF返回对象具有多对多关系,其中两个搜索项匹配相同的字段名,例如,如果模型有一个称为标记的多对多字段,则与某个模型标记相关,然后,DRF可以通过询问?search=cake,baker来找到带有标签

我正在将旧的Django 1.11代码库升级到Django和Django Rest框架的最新版本,但在Django Rest框架的最新版本中使用多个术语时,
?search=…
过滤器是如何工作的,我遇到了一道难题

在DRF版本3.6.3之前,可以执行
?search=term1、term2
端点请求,并使DRF返回对象具有多对多关系,其中两个搜索项匹配相同的字段名,例如,如果模型有一个称为
标记的多对多字段,则与某个模型
标记相关,然后,DRF可以通过询问
?search=cake,baker
来找到带有标签
cake
baker
的对象

在我要提升的代码库中,此代码的(简化)代码如下所示:

class标记QuerySet(models.query.QuerySet):
def公共(自我):
回归自我
类标记(models.Model):
name=models.CharField(unique=True,最大长度=150)
objects=TagQuerySet.as_manager()
def_获取_条目_计数(自身):
返回self.entries.count()
entry\u count=属性(\u get\u entry\u count)
定义(自我):
返回str(self.name)
类元:
排序=['name',]
类条目(models.Model):
title=models.CharField(最大长度=140)
description=models.CharField(最大长度=600,空白=True)
tags=models.ManyToManyField(Tag,related_name='entries',blank=True)
定义(自我):
返回str(self.title)
类元:
详细名称
排序=['-id']
类EntryCustomFilter(filters.FilterSet):
tag=django\u filters.CharFilter(name='tags\u\u name',lookup\u expr='iexact',)
类元:
模型=输入
字段=['标记',]
类EntriesListView(ListCreateAPIView):
"""
-`?search=`-搜索标题、描述和标记
-`&format=json`-返回json格式而非HTML格式的结果
"""
过滤器\后端=(filters.DjangoFilterBackend,filters.SearchFilter,)
filter\u class=EntryCustomFilter
搜索字段=('title','description','tags.\u name',)
解析器\类=(JSONParser,)
然而,
search
的这种行为是无意中得到的,因此现在只有通过多对多字段找到的单个关系匹配所有术语时,DRF才会匹配。因此,一个带有
tags
字段且与
Tag(name=“cake”)
Tag(name=“baker”)
相关的条目不再匹配,因为没有一个标签同时匹配这两个术语,而是一个带有
Tag(name=“baker of cake”)
Tag(name=“teller of tales”)
的条目匹配,因为有一个关系匹配两个术语

至少在撰写本文时,我找不到任何文档可以解释如何实现通用
搜索
过滤器的这种旧行为,我也找不到Stackoverflow上以前提出的关于让DRF再次像这样工作的任何问题(甚至“根本”)。对于名为filters的特定字段,存在一些问题,但对于
search=
,没有问题


那么:在使用DRF版本3.6.4+时,我可以在这里进行哪些更改,以使
?search=…
与以前一样工作?也就是说,如何使多对多字段具有与一个或多个指定术语匹配的独立关系的
?search=term1,term2
过滤器找到模型?

这是DRF中的预期行为,是为了优化M2M搜索/过滤器而引入的。引入此项的原因是为了防止在使用多个术语时发生组合爆炸(有关更多详细信息,请参阅及其相关PR)

为了执行与3.6.3及以下版本中相同类型的匹配,您需要通过扩展
filters.SearchFilter
来创建自定义搜索筛选器类,并为
filter\u queryset
定义添加自定义实现(原始定义可在DRF v3.6.3中找到)

从rest\u框架导入过滤器
进口经营者
从functools导入reduce
从django.db导入模型
从rest\u framework.compat导入
类CustomSearchFilter(filters.SearchFilter):
所需def_m2m_优化(自身、视图):
返回getattr(视图“使用优化”,True)
def get_search_字段(自我、查看、请求):
#对于大于等于3.9.2的DRF版本,请删除此方法,
#因为它已经内置了get_search_字段。
返回getattr(查看“搜索字段”,无)
def链式查询集过滤器(自我、查询集、搜索词、orm查找):
对于搜索词中的搜索词:
查询=[
models.Q(**{orm\u lookup:search\u term})
用于orm_查找中的orm_查找
]
queryset=queryset.filter(reduce(operator.or,查询))
返回查询集
def优化查询集过滤器(自我、查询集、搜索词、orm查找):
条件=[]
对于搜索词中的搜索词:
查询=[
models.Q(**{orm\u lookup:search\u term})
用于orm_查找中的orm_查找
]
附加(reduce(operator.or,查询))
返回查询集过滤器(减少(运算符和条件))
def过滤器查询集(自身、请求、查询集、视图):
search\u fields=self.get\u search\u fields(视图、请求)
search\u terms=self.get\u search\u terms(请求)
如果不搜索\u字段或不搜索\u术语:
返回查询集
orm_查找=[
self.construct\u search(str(search\u字段))
用于搜索字段中的搜索字段
]
base=queryset
如果需要自优化(视图):
queryset=self.optimized\u queryset\u过滤器(queryset、搜索词、orm\u查找)
其他:
queryset=self.chained\u queryset\u过滤器(queryset,搜索词,orm