Django База [2023]: Реализация поиска с помощью PostgreSQL в Django 🔎 #34
Django

Django База [2023]: Реализация поиска с помощью PostgreSQL в Django 🔎 #34

Razilator

Django ORM уже имеются некоторые фильтры для поиска, но они не всегда соответствуют нашим требованиям. Вместо этого мы будем использовать поисковый движок полнотекстового поиска из модуля django.contrib.postgres в PostgreSQL, который обеспечивает широкие возможности для поиска на нашем сайте.

Статья по установке PostgreSQL в Django

Создание представления

Первое, что нам необходимо сделать, это создать нужное предсталвение для реализации поиска. В нашем файле views.py приложения blog добавим следующий код представления:

blog/views.py
from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank
from django.views.generic import ListView


class ArticleSearchResultView(ListView):
    """
    Реализация поиска статей на сайте
    """
    model = Article
    context_object_name = 'articles'
    paginate_by = 10
    allow_empty = True
    template_name = 'blog/articles_list.html'

    def get_queryset(self):
        query = self.request.GET.get('do')
        search_vector = SearchVector('full_description', weight='B') + SearchVector('title', weight='A')
        search_query = SearchQuery(query)
        return (self.model.objects.annotate(rank=SearchRank(search_vector, search_query)).filter(rank__gte=0.3).order_by('-rank'))

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'Результаты поиска: {self.request.GET.get("do")}'
        return context

Данный код представляет собой реализацию поиска статей на сайте. Он использует класс ListView из Django для отображения списка статей, соответствующих запросу пользователя.

В методе get_queryset() происходит поиск статей с помощью полнотекстового поискового движка из модуля django.contrib.postgres.search в PostgreSQL. Для этого формируется поисковый вектор (search_vector), содержащий поля, по которым будет производиться поиск, и задаются веса (weight) каждого поля. Затем формируется поисковый запрос (search_query) на основе запроса пользователя (query), который был передан через GET-параметр do. Поиск выполняется с помощью методов SearchRank и filter модели Article. Результаты сортируются по релевантности в обратном порядке.

Метод get_context_data() формирует контекст для отображения найденных статей в шаблоне.

Обработка представления в urls.py

Следующим действием нам нужно обработать созданное представление в urls.py файле нашего приложения blog:

blog/urls.py
from django.urls import path

from .views import ArticleListView, ArticleDetailView, ArticleByCategoryListView, articles_list, ArticleCreateView, \
    ArticleUpdateView, ArticleDeleteView, CommentCreateView, ArticleByTagListView, ArticleSearchResultView

urlpatterns = [
    path('', ArticleListView.as_view(), name='home'),
    path('articles/', articles_list, name='articles_by_page'),
    path('articles/create/', ArticleCreateView.as_view(), name='articles_create'),
    path('articles/<str:slug>/update/', ArticleUpdateView.as_view(), name='articles_update'),
    path('articles/<str:slug>/delete/', ArticleDeleteView.as_view(), name='articles_delete'),
    path('articles/<str:slug>/', ArticleDetailView.as_view(), name='articles_detail'),
    path('articles/<int:pk>/comments/create/', CommentCreateView.as_view(), name='comment_create_view'),
    path('articles/tags/<str:tag>/', ArticleByTagListView.as_view(), name='articles_by_tags'),
    path('category/<str:slug>/', ArticleByCategoryListView.as_view(), name="articles_by_category"),
    path('search/', ArticleSearchResultView.as_view(), name='search'),
]

Обязательно добавляем юрл в самый конец, для правильной обработки.

Изменение шаблона формы поиска

Переходим в header.html, где наша поисковая форма, и меняем разметку на следующую:

templates/header.html
<form class="col-12 col-lg-auto mb-2 mb-lg-0 me-lg-auto" role="search" method="get" action="{% url 'search' %}">
        <input type="search" class="form-control" placeholder="Search..." aria-label="Search" name='do' autocomplete="off" id="search">
</form>

Проверка работы поисковой системы

Ввел запрос: Django
Ввел запрос: Django
Ввел запрос: Тестовая
Ввел запрос: Тестовая

Отлично. Наш поиск работает так, как нам необходимо.

;