Блог на Django #33: Добавление поиска по блогу

Добавим поисковые возможности в блог. Django ORM позволяет проводить базовые операции по поиску совпадений с помощью, например, фильтра contains (или его версии, учитывающей регистр, icontains). Следующий запрос можно использовать для поиска постов, содержащих слово framework в теле:

from blog.models import Post Post.objects.filter(body__contains='framework')

Но если планируется осуществлять сложный поиск с получением результатов, учитывающих схожесть или разный вес у полей, потребуется полнотекстовый поисковый движок.

Django предлагает мощный поиск, созданный на основе полнотекстового поиска из PostgreSQL. Модуль django.contrib.postgres включает функции, которые есть в PostgreSQL, но которых лишены другие базы данных, поддерживаемые Django. Больше об этом поиске можно узнать здесь: https://www.postgresql.org/docs/10/static/textsearch.html.

Хотя Django и способен работать с любой базой данных, он включает модуль, поддерживающий широкий набор возможностей из PostgreSQL, которых нет в других базах данных, поддерживаемых Django.

Простой поиск

Отредактируйте файл settings.py проекта и добавьте в пункт INSTALLED_APP строку django.contrib.postgres:

INSTALLED_APPS = [ 
    # ... 
    'django.contrib.postgres', 
]

Теперь с помощью search можно проводить поиск:

from blog.models import Post Post.objects.filter(body__search='django')

Этот запрос использует PostgreSQL для создания направления поиска поля body и поискового запроса «django». Результаты основаны на сопоставлении направления и запроса.

Поиск в нескольких полях

Иногда может потребоваться искать в нескольких полях. В этом случае нужно определить SearchVector. Построим вектор, который позволит искать в полях title и body модели Post:

from django.contrib.postgres.search import SearchVector 
from blog.models import Post 

Post.objects.annotate( 
    search=SearchVector('title', 'body'), 
).filter(search='django')

С помощью annotate и SearchVector для обоих полей получается функциональность, которая будет искать совпадения в заголовке и теле постов.

Полнотекстовый поиск — это интенсивный процесс. Если он будет осуществляться в более чем нескольких сотнях строк, нужно определить функциональный индекс, который совпадает с используемым поисковым направлением. Django предлагает поле SearchVectorField для моделей. Подробно об этом можно почитать здесь: https://docs.djangoproject.com/en/2.0/ref/contrib/postgres/search/#perfomance.