Как разделить слова, которые пользователь вставляет в поле ввода в приложении Django
У меня есть строка поиска, которая ищет в 2 моделях колонки title, body, short_description. Я использую базу данных MySQL. Сейчас я использую Q lookups, но есть некоторые ограничения поиска, которые я хотел бы "улучшить".
Один из них заключается в том, что Q-поиск находит результаты только по фразам, которые в точности совпадают с полем, поэтому, например, у меня есть заголовок why python is so amazing? и я должен написать why или python или python is, чтобы получить результаты. Что я хотел бы получить, так это расширить строку поиска, чтобы она работала следующим образом:
Пользователь вводит вопрос в строку поиска: python language и поиск разбивает каждое слово и возвращает все объекты, содержащие python или language. В конечном итоге результат возвращает объект с why python is so amazing?, независимо от того, что пользователь вставляет python language или amazing python.
Ниже я размещаю свой текущий код:
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(), (см. представление) ниже.
models.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, которая перебирает все ключевые слова по заданным полям модели. Большая заслуга в создании этого шаблона менеджера принадлежит Джастину Митчелу превосходная статья о поиске по нескольким моделям.