GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Python 3
  • Скачать Python
  • IDE
  • Скачать PyCharm
  • Django
  • Tkinter
  • Книги

This view

  • Original page
  • New address

GeezerVison is showing python-scripts.com — Создание и настройка поиска на сайте в Джанго (Django Framework)

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

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

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

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

Shell
1
2
3
4
5
$ pipenv install django==2.2.1
$ pipenv shell
$ django-admin startproject citysearch_project .
$ python manage.py migrate
$ python manage.py runserver

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

Django Search

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

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

Shell
1
$ python manage.py startapp cities

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

Python
1
2
3
4
5
# citysearch_project/settings.py
INSTALLED_APPS = [
    ...
    'cities.apps.CitiesConfig', # new
]

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

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
# cities/models.py
from django.db import models
 
 
class City(models.Model):
    name = models.CharField(max_length=255)
    state = models.CharField(max_length=255)
 
    class Meta:
      verbose_name_plural = "cities"
 
    def __str__(self):
        return self.name

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

Python
1
2
$ python manage.py makemigrations cities
$ python manage.py migrate

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

Python
1
$ python manage.py createsuperuser

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

Python
1
2
3
4
5
6
7
8
9
# cities/admin.py
from django.contrib import admin
 
from .models import City
 
class CityAdmin(admin.ModelAdmin):
    list_display = ("name", "state",)
 
admin.site.register(City, CityAdmin)

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

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

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

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

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

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

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

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

Python
1
2
3
4
5
6
7
8
# citysearch_project/urls.py
from django.contrib import admin
from django.urls import path, include # new
 
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('cities.urls')), # new
]

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

Shell
1
$ touch cities/urls.py

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

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

Python
1
2
3
4
5
6
7
8
9
# cities/urls.py
from django.urls import path
 
from .views import HomePageView, SearchResultsView
 
urlpatterns = [
    path('search/', SearchResultsView.as_view(), name='search_results'),
    path('', HomePageView.as_view(), name='home'),
]

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

Python
1
2
3
4
5
6
7
8
9
10
11
12
# cities/views.py
from django.views.generic import TemplateView, ListView
 
from .models import City
 
 
class HomePageView(TemplateView):
    template_name = 'home.html'
 
class SearchResultsView(ListView):
    model = City
    template_name = 'search_results.html'

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

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

Shell
1
2
3
$ mkdir templates
$ touch templates/home.html
$ touch templates/search_results.html

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

Python
1
2
3
4
5
6
7
8
# citysearch_project/settings.py
TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')], # new
        ...
    }
]

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

XHTML
1
2
<!-- templates/home.html -->
<h1>HomePage</h1>

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

Страница Django

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

XHTML
1
2
3
4
5
6
7
8
9
10
<!-- templates/search_results.html -->
<h1>Search Results</h1>
 
<ul>
  {% for city in object_list %}
    <li>
      {{ city.name }}, {{ city.state }}
    </li>
  {% endfor %}
</ul>

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

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

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

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

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

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

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

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

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

Python
1
2
3
4
5
# cities/views.py
class SearchResultsView(ListView):
    model = City
    template_name = 'search_results.html'
    queryset = City.objects.filter(name__icontains='Boston') # новый

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

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

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

Python
1
2
3
4
5
6
7
8
# cities/views.py
...
class SearchResultsView(ListView):
    model = City
    template_name = 'search_results.html'
 
    def get_queryset(self): # новый
        return City.objects.filter(name__icontains='Boston')

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

Объекты Q в Django

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

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

Python
1
2
3
4
5
6
7
8
9
10
11
12
# cities/views.py
from django.db.models import Q # новый
...
 
class SearchResultsView(ListView):
    model = City
    template_name = 'search_results.html'
 
    def get_queryset(self): # новый
        return City.objects.filter(
            Q(name__icontains='Boston') | Q(state__icontains='NY')
        )

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

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

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

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

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

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

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

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

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

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

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

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

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

XHTML
1
2
3
4
5
6
<!-- templates/home.html -->
<h1>HomePage</h1>
 
<form action="{% url 'search_results' %}" method="get">
  <input name="q" type="text" placeholder="Search...">
</form>

Для формы, параметр 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, и передать его дальше в логику нашего приложения.

Python
1
2
3
4
5
6
7
8
9
10
11
12
# cities/views.py
...
class SearchResultsView(ListView):
    model = City
    template_name = 'search_results.html'
 
    def get_queryset(self): # новый
        query = self.request.GET.get('q')
        object_list = City.objects.filter(
            Q(name__icontains=query) | Q(state__icontains=query)
        )
        return object_list

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

Поиск в Django

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

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

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

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

Vasile Buldumac

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.

E-mail: [email protected]

Образование
Universitatea Tehnică a Moldovei (utm.md)

  • 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
  • 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.