0

我有一个搜索栏,它在 2 个模型列标题、正文、short_description 中进行搜索。我正在使用 MySQL 数据库。现在,我正在使用 Q 查找,但我想“改进”一些搜索限制。

其中之一是 Q 查找仅根据与字段完全相同的短语结果查找结果,例如,我有标题,why python is so amazing?我必须写whyor才能获得结果。我想要得到的是扩展搜索栏以按以下方式工作:pythonpython is

用户在搜索栏中插入一个问题:python language搜索查找正在拆分每个单词并返回所有包含pythonor的对象language。最后,结果将返回带有 的对象why python is so amazing?,无论它是用户放置的python language还是amazing python.

我在下面发布我当前的代码:

视图.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我没有得到任何结果。

问题

我将不胜感激有关如何获得基于用户输入输入字段的单词的所有对象列表的结果的任何建议。

4

1 回答 1

0

我遇到了同样的问题,并通过在模型上方的 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关于多模型搜索的出色文章。

于 2022-03-05T19:54:08.060 回答