Для организации поиска на сайте, который основан на Django , и использует базу данных PostgreSQL можно использовать модуль для поиска по этой базе данных, поставляемый с Django. Тем более, что данный поиск обеспечивает полнотекстовый поиск в достаточной мере для небольшого ресурса.
Но для того, чтобы выдача поисковых запросов походила больше на главную страницу, добавим возможность пагинации страниц выдачи, а результаты будут выводиться по 10 штук на одной странице. И для этого также будем использовать модуль django_bootstrap3.
В итоге имеем следующий план действий:
- Добавляем приложение для организации поиска;
- Добавляем url поиска;
- Добавляем форму поиска;
- Описываем шаблон страницы поиска.
- Описываем представление для обработки выдачи поиска;
Добавляем приложение для поиска
Стандартный момент по созданию нового приложения в вашем проекте Django:
- python manage.db startapp search
На выходе получим новое приложение со следующей структурой:
- search/
- migrations/
- __init__.py
- __init__.py
- admin.py
- apps.py
- models.py
- tests.py
- views.py
Подкорректируем немного файл settings.py . Добавим конфигурацию нашего приложения, используется та, что создастся по умолчанию, также воспользуемся двумя модулями:
- Для работы с postgres
- django_bootstrap3
- INSTALLED_APPS = [
- ...
- 'search.apps.SearchConfig',
- 'django.contrib.postgres',
- 'bootstrap3',
- ...
- ]
Добавляем urls поиска
Во-первых, необходимо добавить url шаблон, который отправит запрос в приложение search.
- from django.conf.urls import url, include
- urlpatterns = [
- ...
- url(r'^search/', include('search.urls')),
- ]
Во-вторых, нужно добавить urls.py файл в само приложение search со следующим содержимым, чтобы настроить отправку запроса в представление.
- from django.conf.urls import url
- from . import views
- app_name = 'search'
- urlpatterns = [
- url(r'^$', views.ESearchView.as_view(), name='index'),
- ]
Форма поиска
Форма поиска добавлена в базовый шаблон base.html в приложении home , который будет наследоваться шаблоном страницы поиска.
Приведу тот вариант, который используется на данном сайте с использованием django-bootstrap3
- {% load bootstrap3 %}
- <form action="{% url 'search:index' %}" class="navbar-form navbar-left" method="get">
- <div class="input-group">
- <input id="search" name="q" type="text" class="form-control" placeholder="Поиск">
- <span class="input-group-btn">
- <button type="submit" class="btn btn-default">{% bootstrap_icon 'search' %}</button>
- </span>
- </div>
- </form>
Разберёмся в ключевых моментах:
- В поле action указан адрес куда будет посылаться запрос;
- Будет использоваться метод GET, поскольку пользователь может захотеть поделиться результатом поиска;
- bootstrap_icon подгружает иконки из набора glyphicons.
Шаблон страницы поиска
Для выдачи результатов я использовал организацию внешнего вида такую же, как и на главной странице сайта. Подробнее об этом можете почитать в статье о внедрении пагинации .
Но самым главным отличием от главной страницы является то, что каким-то образом необходимо совместить перелистывание страниц при пагинации и сохранение запроса. Для этого можно подставлять кастомизированный URL в bootstrap_pagination. А именно url=last_question, который будет содержать последний запрос, который был задан в форме поиска. К этому URL автоматически будет добавлен номер страницы.
- {% extends 'home/base.html' %}
- {% load bootstrap3 %}
- {% block page %}
- <h1>Поиск</h1>
- {% if article_lists %}
- {% for article in article_lists %}
- <article>
- <a href="{{ article.get_absolute_url }}">
- <h2>{{ article.article_title }}</h2>
- </a>
- {{ article.desctription|safe }}
- <p><a class="btn btn-default btn-sm" href="{{ article.get_absolute_url }}">Читать далее</a></p>
- </article>
- {% endfor %}
- {% bootstrap_pagination article_lists url=last_question %}
- {% else %}
- <p>Не найдено публикаций по вашему запросу<br>Попробуйте повторить запрос с другой формулировкой</p>
- {% endif %}
- {% endblock %}
Представление поиска
Важным моментом является здесь то, что из запроса необходимо подготовить URL, который будет содержать последний запрос и подставляться в кнопочки пагинации. Иначе при нажатии кнопки пагинации поиск будет ошибочен и скорее всего будете получать ошибку 500 .
- from django.shortcuts import render_to_response
- from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
- from django.views import View
- from knowledge.models import Article
- class ESearchView(View):
- template_name = 'search/index.html'
- def get(self, request, *args, **kwargs):
- context = {}
- question = request.GET.get('q')
- if question is not None:
- search_articles = Article.objects.filter(article_content__search=question)
- # формируем строку URL, которая будет содержать последний запрос
- # Это важно для корректной работы пагинации
- context['last_question'] = '?q=%s' % question
- current_page = Paginator(search_articles, 10)
- page = request.GET.get('page')
- try:
- context['article_lists'] = current_page.page(page)
- except PageNotAnInteger:
- context['article_lists'] = current_page.page(1)
- except EmptyPage:
- context['article_lists'] = current_page.page(current_page.num_pages)
- return render_to_response(template_name=self.template_name, context=context)
Для Django рекомендую VDS-сервера хостера Timeweb .