Django — Урок 034. Как сделать поиск по нескольким моделям данных
Но что, если у вас более одного типа контента. Вы можете иметь статьи, комментарии, форум и сообщения на форуме. Как тогда быть?
Если вы хотите сделать все сами, без использования сторонних библиотек, то вам нужно будет сделать поиск по всем нужным моделям и объединить результат. Я сделал точно так же на сайте.
urls.py
Вам понадобится один класс View, который будет обрабатывать поисковый запрос.
Важным моментом здесь является то, что мы будем обрабатывать запросы на получение, чтобы пользователи могли делиться ссылками с результатами поиска.
В файле urls.py пропишем маршрут для поиска
app_name = 'home' urlpatterns = [ path('search/', views.SearchView.as_view(), name='search'), ]views.py
Допустим, у нас есть несколько типов контента:
Нужно в представлении выполнить поиск по всем видам контента и объединить их в один QuerySet и подготовить к пагинации и выдаче
from itertools import chain from django.shortcuts import render from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage from django.views import View from .models import Article, Comment, Topic, Post class ESearchView(View): template_name = 'search/index.html' def get(self, request, *args, **kwargs): context = <> q = request.GET.get('q') if q: query_sets = [] # Total QuerySet # Searching for all models query_sets.append(Article.objects.search(query=q)) query_sets.append(Comment.objects.search(query=q)) query_sets.append(Topic.objects.search(query=q)) query_sets.append(Post.objects.search(query=q)) # and combine results final_set = list(chain(*query_sets)) final_set.sort(key=lambda x: x.pub_date, reverse=True) # Sorting context['last_question'] = '?q=%s' % q current_page = Paginator(final_set, 10) page = request.GET.get('page') try: context['object_list'] = current_page.page(page) except PageNotAnInteger: context['object_list'] = current_page.page(1) except EmptyPage: context['object_list'] = current_page.page(current_page.num_pages) return render(request=request, template_name=self.template_name, context=context)Нюанс приведенного выше кода в том, что мы объединяем все модели данных, а также сортируем их по дате. Чтобы это стало возможным, мы будем использовать возможности языка программирования Python, а именно утиную типизацию. Сортировка по дате стала возможной благодаря тому, что во всех моделях данных есть поле даты публикации с одинаковым названием pub_date.
В общем, это очень важно, когда вы пытаетесь назвать поля моделей данных одинаково для разных моделей данных. Это позволяет вам очень гибко разрабатывать сайт Django и использовать утиную типизацию для написания шаблонов для отображения данных, которые не зависят от конкретного типа данных, а скорее зависят от интерфейса, который поддерживает ваши модели данных.
Также интересно то, что объекты всех моделей данных, которые представлены в этом коде, имеют один и тот же метод поиска. Этот метод не является стандартным. Для его реализации нужно написать свой менеджер моделей и назначить его на поле объектов.
ArticleManager
Рассмотрим типовой менеджер статей. Мы наследуем его от базового менеджера моделей и определяем метод поиска с помощью логики поиска. Аналогично нужно прописать этот метод для всех моделей, в которых будет производиться поиск.
from django.db import models from django.db.models import Q class ArticleManager(models.Manager): use_for_related_fields = True def search(self, query=None): qs = self.get_queryset() if query: or_lookup = (Q(title__icontains=query) | Q(content__icontains=query)) qs = qs.filter(or_lookup) return qsУстановка менеджера в модель
class Article(models.Model): objects = ArticleManager()search/index.html
А для шаблона поиска можно использовать немного измененный шаблон из одной из первых статей по организации поиска.
Поиск
>">>
>
>">Читать далее
Не найдено публикаций по вашему запросу
Попробуйте повторить запрос с другой формулировкойЯ специально использую в данном случае параметр обезличенного объекта, который не имеет указания на конкретный тип контента, поэтому было понятно, что там может быть любой объект контента. Главное, чтобы все методы были реализованы для всех моделей, которые используются в этом шаблоне.
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
Рекомендуемые статьи по этой тематике
- Django - Урок 063. Полнотекстовый поиск на сайте для нескольких моделей с поддержкой мультиязычности
- Django - Урок 033. Передача списка аргументов в метод order_by для сортировки QuerySet
- Django - Урок 032. Расширенные параметры поиска
- Django - Урок 012. Внедрение поиска по сайту с пагинацией результатов
По статье задано0 вопрос(ов)
Подписка на обсуждение 3
Подписка на раздел 176
Вам это нравится? Поделитесь в социальных сетях!
Руководство по созданию поиска на сайте в Django

В данном руководстве мы освоим базовый поиск по сайту Django и затронем способы улучшить его с более продвинутыми возможностями.
Полный исходный код можно найти на GitHub.
Для начала, давайте создадим новый проект Django (перейдите сюда, если нужна помощь). В вашей командной строке, введите следующие команды для установки последней версии при помощи Pipenv, создайте проект под названием citysearch_project , настройте внутреннюю базу данных через migrate и запустите локальный веб сервер при помощи runserver .
$ 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.

Создаем приложение Cities в Django
Теперь мы создадим одно приложение под названием cities для хранения списка названий городов. Мы осознанно не будем выходить за рамки простых основ. Остановите локальный сервер при помощи Ctrl+C и используйте команду startapp для создания нашего нового приложения.
$ python manage .py startapp cities
Затем обновите INSTALLED_APPS внутри нашего файла settings.py , чтобы сообщить Django о новом приложении.
# citysearch_project/settings.py
INSTALLED_APPS = [
'cities.apps.CitiesConfig' , # new
Теперь перейдем к моделям. Мы назовем нашу единственную модель City . В ней будет два поля: name и state . Так как админка Django по умолчанию будет менять имя приложения во множественном числе на Citys , мы также настроим verbose_name_plural . И наконец настроим __str__ для отображения названия города.
# 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 manage . py makemigrations cities
$ python manage . py migrate
Есть несколько способов наполнить базу данных, но самый простой, на мой взгляд, это через admin. Создайте аккаунт суперпользователя, чтобы мы смогли зайти в админку.
$ python manage . py createsuperuser
Теперь нам нужно обновить cities/admin.py для отображения нашего приложения внутри админки.
# 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 , затем зайдите в свой аккаунт суперпользователя.

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

Домашняя страница и страница выдачи поиска Django
У нас есть заполненная база данных, однако все еще есть несколько шагов, которые нужно выполнить, перед тем как она может быть отображена на нашем сайте Django. В конце концов, нам нужна только домашняя страница и страница выдачи поиска. Каждой странице нужен надлежащий вид, url и шаблон. Порядок, в котором мы их будем создавать не принципиальный. Все должно быть на сайте для правильной работы.
В целом, я предпочитаю начинать с URL-ов, добавить views , и в конце создать шаблоны, чем мы и займемся.
Сначала нам нужно добавить путь URL для нашего приложения, это можно сделать, импортировав include и настроив путь к нему.
# 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 , если он еще работает.
$ touch cities / urls .py
Внутри этого файла мы импортируем еще не созданные представления ( views ) для каждой HomePageView и SearchResultsView , и указать путь к каждому из них. Обратите внимание на то, что мы указываем опциональное название URL для каждого из них.
Вот так это будет выглядеть:
# 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 .
# 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 .
$ mkdir templates
$ touch templates / home .html
$ touch templates / search_results .html
Обратите внимание на то, что нам также нужно обновить наш settings.py , чтобы указать Django на проектную папку с шаблонами. Это вы можете найти в разделе TEMPLATES .
# citysearch_project/settings.py
'DIRS' : [ os.path . join ( BASE_DIR , 'templates' ) ] , # new
Домашная страница выведет только заголовок.
HomePage
Запустите веб сервер еще раз при помощи python manage.py runserver . Теперь мы можем увидеть домашнюю страницу на http://127.0.0.1:8000/ .

Теперь, для страницы поисковой выдачи, которая будет выполнять цикл на object_list , вернется имя от контекстного объекта ListView . Затем мы выведем name и state для каждой записи из базы данных.
Search Results
Все готово! Наша страница поисковой выдачи доступна на http://127.0.0.1:8000/search/ .

Формы и наборы запросов в Django
В конечном итоге базовая реализация поиска сводится к форме, которая передает пользовательский запрос — сам фактический поиск — и затем к набору запросов, который будет фильтровать результаты на основе этого запроса.
Мы можем начать с любого из них, но мы начнем с настройки фильтрации, после чего перейдем к форме.
Базовая фильтрация запросов в Django
В Django, QuerySet используется для фильтрации выдачи из модели базы данных. В данный момент, наша модель City выводит все свое содержимое. В итоге нам нужно ограничить страницу поисковой выдачи для фильтрации выведенных результатов, на основании поискового запроса от пользователя.
Есть несколько способов настроить набор запросов, и фактически возможно выполнить фильтрацию через менеджер самой модели, однако, чтобы сохранять простоту решений, мы можем добавить фильтр всего в одну строку. Давайте сделаем это.
Здесь мы обновляем метод queryset из ListView и добавляем фильтр, так что возвращается только город под названием Бостон . В итоге, мы заменим это переменной, которая представляет пользовательский поисковый запрос.
# cities/views.py
class SearchResultsView ( ListView ) :
model = City
template_name = 'search_results.html'
queryset = City . objects . filter ( name__icontains = 'Boston' ) # новый
Обновите страницу поисковой выдачи и вы увидите, что отображается только Бостон .

Также можно настроить queryset , переопределив метод get_queryset() , для изменения списка выданных городов. Явного преимущества в этом для нас нет, но этот подход мне кажется более гибким, чем просто указать атрибуты набора запросов.
# 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 вверху файла, и затем слегка поменять наш существующий запрос
# 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' )
Обновите вашу страницу поисковой выдачи, чтобы увидеть результат.

Теперь, вернемся к нашей HTML-форме поиска для замены текущих прописанных значений переменными поискового запроса.
Формы для ввода данных на сайте в Django
По сути, веб формы — это просто: они берут ввод пользователя и направляют его в URL либо через метод GET , либо через POST . Однако на практике, это фундаментальное поведение веба может быть монструозно сложным.
Первая проблема — это отправка данных формы: куда на самом деле идут данные, и как мы их будет обрабатывать? Не говоря уже о множественных проблемах с безопасностью, когда вы разрешаете пользователям отправлять данные на веб-сайт.
Существует только два варианта того, как отправлять форму: либо через HTTP метод GET , либо через POST .
POST связывает данные формы, кодирует их для передачи, отправляет их на сервер и затем получает ответ. Любой запрос, который меняет состояние базы данных (создает, редактирует, или удаляет данные) — должен использовать POST .
GET связывает данные формы в строку, которая вносится в URL. GET должен быть использован для такого запроса, который не влияет на состояние приложения, например — поиск, где ничего внутри базы данных не меняется. Мы просто выполняем отфильтрованный просмотр списка.
Если вы взгляните на URL после поиска в гугле, вы увидите свой поисковый запрос в самом URL страницы результатов поиска ?q= .
Для дополнительной информации, Mozilla предоставляет подробные руководства как для отправки данных из формы, так и валидации форм данных, с которыми стоит ознакомиться, если вы не владеете основами.
Поисковая форма для сайта на Django
Впрочем, для наших целей, мы можем создать базовую форму поиска к существующей домашней странице уже сейчас. Вот так это выглядит. Мы рассмотрим каждую часть примера ниже.
Как создать базовый поиск для сайта Django?
Главная страница » Новости » Как создать базовый поиск для сайта Django?
11 апреля 2021

Конкретный контент любого сайта обычно извлекается пользователями через поиск Google, Yandex или другие поисковые системы. Однако, если этот вариант поиска реализован на веб-сайте, пользователи могут легко найти желаемый контент на сайте без использования поиска Google. Еще одно преимущество добавления опции поиска на веб-сайт заключается в том, что разработчик может правильно управлять результатами поиска. Это означает, что он может контролировать, какое содержимое сайта будет отображаться или нет. В этой статье будет показан процесс реализации базового поиска на сайте Django.
Предпосылки:
Перед тем, как практиковать сценарий этого руководства, вам необходимо выполнить следующие задачи:
- Установите Django версии 3+ на Ubuntu 20+ (желательно)
- Создайте проект Django
- Запустите сервер Django, чтобы проверить, работает ли сервер правильно или нет.
Настройте приложение Django:
Выполните следующую команду, чтобы создать приложение Django с именем searchchapp.
$ python3 manage.py startapp searchapp
Выполните следующую команду, чтобы создать пользователя для доступа к базе данных Django. Если вы создали пользователя раньше, вам не нужно запускать команду.
$ python3 manage.py createsuperuser
Добавьте имя приложения в часть INSTALLED_APP файла settings.py.
INSTALLED_APPS = [ ….. 'searchapp' ]
Создайте папку с именем templates внутри папки searchchapp и укажите местоположение шаблона приложения в части TEMPLATES файла settings.py.
TEMPLATES = [ < …. 'DIRS': ['/home/fahmida/django_pro/searchapp/templates'], …. >, ]
Создать модели:
Измените файл models.py с помощью следующего сценария. Здесь были определены два класса для создания двух реляционных таблиц с именами booktypes и books. Поле типа таблицы книг — это внешний ключ, который появится из таблицы типов книг.
models.py
# Импортировать необходимые модули from django.db import models from django.urls import reverse # Создать модель class Booktype(models.Model): btype = models.CharField(max_length=100, unique=True) class Meta: ordering=('btype',) # Создайте модель gor book class Book(models.Model): book_name = models.CharField(max_length=150) author_name = models.CharField(max_length=150) type = models.ForeignKey(Booktype, on_delete=models.CASCADE) price = models.FloatField() publication = models.CharField(max_length=100) class Meta: ordering=('book_name',) def __str__(self): return self.book_name def get_url(self): return reverse('book_detail', args=[self.id])
Создать шаблоны для поиска:
Для создания функции поиска, показанной в этой статье, вам потребуются три файла HTML. Это book_list.html, book_detail.html и search.html. Book_list.html отобразит все записи из таблицы books. Book_detail.html отобразит подробную информацию о конкретной книге. Search.html отобразит результат поиска после отправки формы поиска.
book_list.html
Book List
