Руководство по созданию поиска на сайте в Django

Поиск на сайте в Django

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

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

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

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

Django Search

Создаем приложение 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, затем зайдите в свой аккаунт суперпользователя.

Django панель администратора

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

Админка Django примеры

Домашняя страница и страница выдачи поиска 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/.

Страница Django

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

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

Django результаты поиска

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

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

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

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

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

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

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

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

Django поисковая выдача

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

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

Объекты Q в Django

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

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

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

Фильтрация Q в Django

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

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

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

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

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

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

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

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

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

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

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

Для формы, параметр action определяет, куда направлять пользователя после нажатия на кнопку поиска. Мы используем URL нашей страницы поисковой выдачи. Затем мы определим использование GET в качестве нашего метода.

Пример кода из данной статьи будет работать и на полноценном сервере, можете выбрать хостинг для проектов на Python которые поддерживают фреймворк Django и запустить свой собственный сайт на Python в интернете.

Внутри нашего одиночного ввода возможно иметь несколько вводов, или добавить кнопку по желанию. Мы назовем ее q, к чему мы и сошлемся далее. Определяем type как text. Затем добавляем значение к placeholder для запроса пользователя.

И все! Теперь, попробуйте ввести запрос на главной странице, например — san diego.

Поиск на Django

После нажатия кнопки Enter, вас перенаправит на страницу поисковой выдачи. Обратите внимание на то, что URL содержит наш поисковый запрос: http://127.0.0.1:8000/search/?q=san+diego.

Поиск на Django

Однако результат не изменился! Это связано с тем, что наш SearchResultsView все еще содержит изначально вписанные значения. Последний шаг — это взять пользовательский поисковый запрос, представленный нашим q bp URL, и передать его дальше в логику нашего приложения.

Мы добавили переменную запроса, которая принимает значение q из формы поискового запроса. Далее, мы обновляем наш фильтр для названий города и штата. И все! Обновите страницу поисковой выдачи — у нее все еще тот же URL с нашим запросом, и мы получаем ожидаемый результат.

Поиск в Django

Если вы хотите сравнить свой код с официальным источником, вы можете найти его на GitHub (ссылку мы указали в начале этого урока).

Дальнейшие шаги

Наши основы поиска в Django готовы и изучены! Может, вы хотите добавить кнопку в поисковую форму, которую также можно нажать, как и Enter? Или хотите добавить какую-нибудь валидацию формы?

Помимо фильтрации с использованием AND и OR, есть и другие факторы, если вам нужен поиск уровня гугла с релевантностью и прочим. На этом выступлении DjangoCon 2014 показывается, насколько глубока может быть поисковая кроличья нора!