我有一个搜索栏,在两个模型列title、body、short_description中进行搜索。我正在使用MySQL数据库。现在,我正在使用Q查找,但有一些搜索限制,我想"改进"。
其中之一是Q查找仅根据与字段中完全相同的短语结果找到结果,因此例如,我的标题为why python is so amazing?
,必须写why
、python
或python is
才能获得结果。我想得到的是以以下方式扩展搜索栏:
用户在搜索栏中插入一个问题:python language
,搜索查找是拆分每个单词并返回包含python
或language
的所有对象。最终,无论用户放置python language
还是amazing python
,结果都将返回具有why python is so amazing?
的对象。
我在下面发布我当前的代码:
views.py
def search_items(request):
query = request.GET.get('q')
article_list= Article.objects.filter(title__icontains=query)
qa_list = QA.objects.filter(title__icontains=query)
if query is not None:
lookups = Q(title__icontains=query) | Q(short_description__icontains=query) | Q(body__icontains=query)
article_list= Article.objects.filter(lookups, status=1).distinct()
qa_list = QA.objects.filter(lookups, status=1).distinct()
context = {
'query_name': query,
'article_list': article_list,
'qa_list': qa_list,
}
return render(request, 'search/search_items.html', context)
我已经检查了这个解决方案和这个解决方案,但结果并不令人满意,因为当我放置python language
来查找标题为why python is so amazing
的对象时,我没有得到任何结果。
问题
对于如何获得基于用户输入字段中的单词的所有对象列表的对象,我将不胜感激。
我遇到了同样的问题,并通过在模型上方的models.py中添加一个自定义搜索管理器来解决它。管理器有两种方法,一种用于单词搜索,另一种用于多词搜索。使用.split()
将查询字符串拆分为单词列表(请参见下面的视图(。
型号.py
class MyModelSearchManager(models.QuerySet):
def search(self, query=None):
qs = self
if query is not None:
or_lookup = (Q(some_field__icontains=query))
qs = qs.filter(or_lookup).distinct()
return qs
def search_and(self, query=None):
qs = self
if query is not None:
or_lookup = reduce(lambda x, y: x & y, [Q(some_field__icontains=word) for word in query])
qs = qs.filter(or_lookup).distinct()
return qs
class MyModelManager(models.Manager):
def get_queryset(self):
return MyModelSearchManager(self.model, using=self._db)
def search(self, query=None):
return self.get_queryset().search(query=query)
def search_and(self, query=None):
return self.get_queryset().search_and(query=query)
当然,在您的模型字段下面声明自定义管理器:
objects = MyModelManager()
然后,在您的视图中,拆分搜索字符串并区分单个单词搜索和多单词搜索:
class SearchView(ListView):
template_name = 'my_app_templates/search_results.html'
count = 0
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['count'] = self.count or 0
context['query'] = self.request.GET.get('q')
return context
def get_queryset(self):
request = self.request
query_list = request.GET.get('q', None).split()
query_list_count = len(query_list)
if query_list is not None:
if query_list_count == 1:
qs = MyModel.objects.search(query=query_list[0]).order_by('-date_added')
self.count = len(qs)
elif query_list_count > 1:
qs = MyModel.objects.search_and(query=query_list).order_by('-date_added')
self.count = len(qs)
result_count = len(qs)
create_search_record(self, request, query_list, query_list_count, result_count)
return qs
对于多单词字符串,神奇之处在于reduce
函数,它尝试针对给定的模型字段使用所有关键字。这种经理人模式在很大程度上归功于Justin Mitchel在多模式搜索方面的出色表现。