В данном руководстве мы освоим базовый поиск по сайту Django и затронем способы улучшить его с более продвинутыми возможностями.

Полный исходный код можно найти на GitHub.

Для начала, давайте создадим новый проект Django (перейдите сюда, если нужна помощь). В вашей командной строке, введите следующие команды для установки последней версии при помощи Pipenv, создайте проект под названием citysearch_project , настройте внутреннюю базу данных через migrate и запустите локальный веб сервер при помощи runserver .

Если вы перейдете на http://127.0.0.1:8000/ , вы увидите приветствие Django, которое подтверждает, что все настроено правильно. Локальный сервер не выражает все моменты реальной работы сайта на сервере, можете ознакомиться со списком хостингов https://hostinghub.ru/top/vds на которых вы можете запустить полноценный сайт на Python.

Создаем приложение Cities в Django

Теперь мы создадим одно приложение под названием cities для хранения списка названий городов. Мы осознанно не будем выходить за рамки простых основ. Остановите локальный сервер при помощи Ctrl+C и используйте команду startapp для создания нашего нового приложения.

Затем обновите INSTALLED_APPS внутри нашего файла settings.py , чтобы сообщить Django о новом приложении.

Теперь перейдем к моделям. Мы назовем нашу единственную модель City . В ней будет два поля: name и state . Так как админка Django по умолчанию будет менять имя приложения во множественном числе на Citys , мы также настроим verbose_name_plural . И наконец настроим __str__ для отображения названия города.

Отлично, все настроено. Мы можем создать файл миграции для этого изменения, затем добавить его в нашу базу данных через migrate .

Есть несколько способов наполнить базу данных, но самый простой, на мой взгляд, это через admin. Создайте аккаунт суперпользователя, чтобы мы смогли зайти в админку.

Теперь нам нужно обновить cities/admin.py для отображения нашего приложения внутри админки.

Еще раз запустите сервер при помощи python manage.py runserver и направьтесь в админку по http://127.0.0.1:8000/admin , затем зайдите в свой аккаунт суперпользователя.

Нажмите на раздел cities и добавьте несколько записей. Здесь видно четыре моих примера.

Домашняя страница и страница выдачи поиска Django

У нас есть заполненная база данных, однако все еще есть несколько шагов, которые нужно выполнить, перед тем как она может быть отображена на нашем сайте Django. В конце концов, нам нужна только домашняя страница и страница выдачи поиска. Каждой странице нужен надлежащий вид, url и шаблон. Порядок, в котором мы их будем создавать не принципиальный. Все должно быть на сайте для правильной работы.

В целом, я предпочитаю начинать с URL-ов, добавить views , и в конце создать шаблоны, чем мы и займемся.

Сначала нам нужно добавить путь URL для нашего приложения, это можно сделать, импортировав include и настроив путь к нему.

Далее, нам нужнен файл urls.py внутри приложения cities , однако Django не создает такой для нас по команде startapp . Не нужно беспокоиться, мы можем создать его в командной строке. Останавливаем сервер при помощи Ctrl+C , если он еще работает.

Внутри этого файла мы импортируем еще не созданные представления ( views ) для каждой HomePageView и SearchResultsView , и указать путь к каждому из них. Обратите внимание на то, что мы указываем опциональное название URL для каждого из них.

Вот так это будет выглядеть:

В третьих, нам нужно настроить наши два представления ( views ). Домашняя страница будет простым шаблоном с итоговой поисковой строкой. Для Django отлично подойдет TemplateView для этой цели. Страница поисковой выдачи упорядочит необходимые результаты, что хорошо ложится под ListView .

Последний шаг — наши шаблоны. Мы можем добавить шаблоны внутри нашего приложения cities , однако я нашел более простой подход, а именно — создание папку проектных шаблонов.

Создайте папку с шаблонами и затем оба шаблона: home.html и search_results.html .

Обратите внимание на то, что нам также нужно обновить наш settings.py , чтобы указать Django на проектную папку с шаблонами. Это вы можете найти в разделе TEMPLATES .

Домашная страница выведет только заголовок.

Запустите веб сервер еще раз при помощи python manage.py runserver . Теперь мы можем увидеть домашнюю страницу на http://127.0.0.1:8000/ .

Теперь, для страницы поисковой выдачи, которая будет выполнять цикл на object_list , вернется имя от контекстного объекта ListView . Затем мы выведем name и state для каждой записи из базы данных.

Все готово! Наша страница поисковой выдачи доступна на http://127.0.0.1:8000/search/ .

Формы и наборы запросов в Django

В конечном итоге базовая реализация поиска сводится к форме, которая передает пользовательский запрос — сам фактический поиск — и затем к набору запросов, который будет фильтровать результаты на основе этого запроса.

Мы можем начать с любого из них, но мы начнем с настройки фильтрации, после чего перейдем к форме.

Базовая фильтрация запросов в Django

В Django, QuerySet используется для фильтрации выдачи из модели базы данных. В данный момент, наша модель City выводит все свое содержимое. В итоге нам нужно ограничить страницу поисковой выдачи для фильтрации выведенных результатов, на основании поискового запроса от пользователя.

Есть несколько способов настроить набор запросов, и фактически возможно выполнить фильтрацию через менеджер самой модели, однако, чтобы сохранять простоту решений, мы можем добавить фильтр всего в одну строку. Давайте сделаем это.

Здесь мы обновляем метод queryset из ListView и добавляем фильтр, так что возвращается только город под названием Бостон . В итоге, мы заменим это переменной, которая представляет пользовательский поисковый запрос.

Обновите страницу поисковой выдачи и вы увидите, что отображается только Бостон .

Также можно настроить queryset , переопределив метод get_queryset() , для изменения списка выданных городов. Явного преимущества в этом для нас нет, но этот подход мне кажется более гибким, чем просто указать атрибуты набора запросов.

Большую часть времени, встроенных методов filter() , all() , get() , или exclude() из QuerySet будет достаточно. Однако есть очень надежный и детализированный API QuerySet.

Объекты Q в Django

Использование filter() — эффективно, с ним даже можно связать фильтры вместе. Однако, вам могут понадобиться более сложные запросы, такие как ИЛИ (OR) . В таких случаях приходит время объектов Q.

Вот пример того, где мы настраиваем фильтр на поиск результата, который совпадает с названием города Бостон , или название штата, которое содержит аббревиатуру NY . Это также просто, как импорт Q вверху файла, и затем слегка поменять наш существующий запрос

Обновите вашу страницу поисковой выдачи, чтобы увидеть результат.

Теперь, вернемся к нашей HTML-форме поиска для замены текущих прописанных значений переменными поискового запроса.

Формы для ввода данных на сайте в Django

По сути, веб формы — это просто: они берут ввод пользователя и направляют его в URL либо через метод GET , либо через POST . Однако на практике, это фундаментальное поведение веба может быть монструозно сложным.

Первая проблема — это отправка данных формы: куда на самом деле идут данные, и как мы их будет обрабатывать? Не говоря уже о множественных проблемах с безопасностью, когда вы разрешаете пользователям отправлять данные на веб-сайт.

Существует только два варианта того, как отправлять форму: либо через HTTP метод GET , либо через POST .

POST связывает данные формы, кодирует их для передачи, отправляет их на сервер и затем получает ответ. Любой запрос, который меняет состояние базы данных (создает, редактирует, или удаляет данные) — должен использовать POST .

GET связывает данные формы в строку, которая вносится в URL. GET должен быть использован для такого запроса, который не влияет на состояние приложения, например — поиск, где ничего внутри базы данных не меняется. Мы просто выполняем отфильтрованный просмотр списка.

Если вы взгляните на URL после поиска в гугле, вы увидите свой поисковый запрос в самом URL страницы результатов поиска ?q= .

Для дополнительной информации, Mozilla предоставляет подробные руководства как для отправки данных из формы, так и валидации форм данных, с которыми стоит ознакомиться, если вы не владеете основами.

Поисковая форма для сайта на Django

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

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

Но для того, чтобы выдача поисковых запросов походила больше на главную страницу, добавим возможность пагинации страниц выдачи, а результаты будут выводиться по 10 штук на одной странице. И для этого также будем использовать модуль django_bootstrap3.

В итоге имеем следующий план действий:

  1. Добавляем приложение для организации поиска;
  2. Добавляем url поиска;
  3. Добавляем форму поиска;
  4. Описываем шаблон страницы поиска.
  5. Описываем представление для обработки выдачи поиска;

Добавляем приложение для поиска

Стандартный момент по созданию нового приложения в вашем проекте Django:

На выходе получим новое приложение со следующей структурой:

Подкорректируем немного файл settings.py . Добавим конфигурацию нашего приложения, используется та, что создастся по умолчанию, также воспользуемся двумя модулями:

  1. Для работы с postgres
  2. django_bootstrap3

Добавляем urls поиска

Во-первых, необходимо добавить url шаблон, который отправит запрос в приложение search.

Во-вторых, нужно добавить urls.py файл в само приложение search со следующим содержимым, чтобы настроить отправку запроса в представление.

Форма поиска

Форма поиска добавлена в базовый шаблон base.html в приложении home , который будет наследоваться шаблоном страницы поиска.

Приведу тот вариант, который используется на данном сайте с использованием django-bootstrap3

Разберёмся в ключевых моментах:

  1. В поле action указан адрес куда будет посылаться запрос;
  2. Будет использоваться метод GET, поскольку пользователь может захотеть поделиться результатом поиска;
  3. bootstrap_icon подгружает иконки из набора glyphicons.

Шаблон страницы поиска

Для выдачи результатов я использовал организацию внешнего вида такую же, как и на главной странице сайта. Подробнее об этом можете почитать в статье о внедрении пагинации .

Но самым главным отличием от главной страницы является то, что каким-то образом необходимо совместить перелистывание страниц при пагинации и сохранение запроса. Для этого можно подставлять кастомизированный URL в bootstrap_pagination. А именно url=last_question, который будет содержать последний запрос, который был задан в форме поиска. К этому URL автоматически будет добавлен номер страницы.

Представление поиска

Важным моментом является здесь то, что из запроса необходимо подготовить URL, который будет содержать последний запрос и подставляться в кнопочки пагинации. Иначе при нажатии кнопки пагинации поиск будет ошибочен и скорее всего будете получать ошибку 500 .

Для Django рекомендую VDS-сервера хостера Timeweb .

Рекомендуем хостинг TIMEWEB

Рекомендуемые статьи по этой тематике

Пользователи ищут товары в интернет-магазине, ищут стати, поиск это неотъемлемый компонент сайта. Быстрый и гибкий поиск сложно реализовать средствами реляционных баз данных. Для таких задач используют поисковые движки, один из которых Elasticsearch. Elasticsearch хорошо документирован и доступен из коробки на AWS.

Для работы с elasticsearch используется библиотека elasticsearch-py или elasticsearch-dsl-py. elasticsearch-dsl-py это надстройка над elasticsearch-py, она проста в использовании и поддерживает elasticsearch версии 5.x. На базе этой библиотеки была создана библиотека django-rest-elasticsearch, которая основана на идеологии существующего поиска в Django REST Framework. Ниже я детально распишу как реализовать поиск в Django REST Framework с помощью elasticsearch используя данную библиотеку.

В качестве примера рассмотрим реализацию простого блога с фильтрацией по тегам и поиском по заголовку статей.

Установка

Процесс установки elasticsearch и django детально расписан в официальных документациях. С установкой пакета все достаточно просто

Создание модели и индекса

После создания модели опишем нашу модель в виде elasticsearch документа.

Теперь можно создать индекс в elasticsearch

Автоматическое обновление документов в elasticsearch

После создания модели и индекса, нужно что бы любые изменения в нашей модели были отображены в elasticsearch. Наилучшим средством это сделать добавить django сигнал, который отправить уведомления когда будут происходит изменения в модели. Прежде чем создать сигнал создадим сериалайзер для преобразования django объекта в документ elasticsearch

Теперь добавим сигнал

После добавления сигнала, любые изменения в модели моментально будут сделаны в elasticsearch

Создание view

Приступим к создания view для поиска и фильтрации

Вот и все, примеры поиска

Полный код примера доступен на github. Надеюсь что статья поможет Вам реализовать поиск в Вашем проекте.