Как сделать поиск django

Обновлено: 05.07.2024

Установить Django на своём хосте довольно просто - можете изучить инструкцию ниже.

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

На многих современных хостингах процедура будет похожей.

Установка Django

Первым делом советую обновить pip

python3 -m pip install --upgrade pip

Затем непосредственно установить Django

python3 -m pip install django

python3 -m django --version

python3 -m pip list

Package Version ----------------- -------- asgiref 3.3.4 Django 3.2.4 pip 21.1.2 pytz 2021.1 setuptools 39.0.1 sqlparse 0.4.1 typing-extensions 3.10.0.0

Команды Django

Список комад Django можно получить выполнив

python3 -m django help

Type 'python -m django help ' for help on a specific subcommand. Available subcommands: [django] check compilemessages createcachetable dbshell diffsettings dumpdata flush inspectdb loaddata makemessages makemigrations migrate runserver sendtestemail shell showmigrations sqlflush sqlmigrate sqlsequencereset squashmigrations startapp startproject test testserver Note that only Django core commands are listed as settings are not properly configured (error: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.).

В каждом проекте (project) обычно используется одно или несколько приложений (application)

Когда все приложения и конфигурации объединены они составляют веб-приложение.

applications + configurations = web application

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

python3 manage.py startapp first_app

Появится директория first_app в которой будут следующие файлы

Переходим в директорию Project_Name/Project_Name

Редактируем файл Project_Name/Project_Name/settings.py

Нужно добавить в список установленных приложений наше новое приложение first_app

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'first_app', ]

python3 manage.py runserver

Если перезапуск осуществляется с помощью скрипта выполняем (насколько я знаю, это актуально для хостингов beget и dreamhost)

Создаём view и связываем с url

Процесс состоит минимум из трёх действий

  1. В директории с приложением, например Project_Name/first_app в файле views.py нужно создать функцию, которая будет слушать url
  2. В главной директории проекта, например Project_Name/Project_Name в файле urls.py нужно импортировать эту функцию
  3. По-прежнему в urls.py нужно добавить сочетание url и функции в urlpatterns

Пример: Переходим в директорию с приложением Project_Name/first_app и редактируем views.py , чтобы создать наш первый view.

Добавляем следущий код в файл Project_Name/first_app/views.py:

from django.http import HttpResponse def about (request): return HttpResponse("About Us!")

Теперь нужно привязать этот view к какой-то url

Добавляем следующий код в файл urls.py

from first_app.views import about urlpatterns = [ path( '' , 'about') ]

В urlpatterns можно указывать url разными способами

Обратите внимание на welcome - одна функция может обслуживать несколько url

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


Этот набор инструкций напомнит вам об основных операциях с Django, если вы работаете над веб-проектом. Сюда входят такие действия, как установка Django, запуск проекта, работа с моделями, создание домашней страницы, использование шаблонов и создание учётных записей пользователей.

Шпаргалка предназначена для тех, кто уже знаком с Python, понимает, что такое виртуальное окружение, и имеет начальные знания о веб-разработке.

Что такое Django?

Django — веб-фреймворк для создания интерактивных веб-сайтов на Python. В Django вы определяете тип данных, с которыми ваш сайт должен работать, а затем указываете, как пользователи могут взаимодействовать с этими данными. Все описанные ниже действия актуальны для Django 3.0.

Установка Django

Лучше установить Django в виртуальном окружении — virtualenv или pipenv, где ваш проект будет изолирован от других. Большинство команд, приведённых ниже, предполагают, что вы работаете в виртуальной среде.

Создать виртуальную среду

pipenv:

Активировать среду

venv, macOS and Linux:

venv, Windows:

pipenv:

Установить Django в активную среду

pipenv:

Создание проекта

Чтобы начать работу, мы создадим новый проект и базу данных, а затем запустим веб-сервер. Во всех примерах ниже проект будет называться learning_log .

Создать новый проект

Создать базу данных

Посмотреть проект

Создать новое приложение

Проект Django состоит из одного или нескольких приложений.

Перезапуск сервера разработки

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

Работа с моделями

Данные в проекте Django представлены в виде набора моделей — объектов Python, определяющих структуру хранения этих данных.

Определение модели

Чтобы определить модель для вашего приложения, измените файл models.py , созданный в папке приложения. Метод __str __() сообщает Python, как отображать экземпляр модели в строковом представлении. Django использует этот механизм для отображения объектов в формах.

Активация модели

Для использования модели приложение должно быть добавлено в список INSTALLED_APPS , который хранится в файле settings.py проекта.

Миграция базы данных

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

Создание суперпользователя

Суперпользователь — это учётная запись с доступом ко всем компонентам проекта.

Создание новой модели

Новая модель может использовать существующую модель. Атрибут ForeignKey устанавливает связь между экземплярами двух связанных моделей. Обязательно мигрируйте базу данных после добавления новой модели в ваше приложение.

Определение модели с внешним ключом:

Создание простой домашней страницы

Пользователи взаимодействуют с проектом через веб-страницы. Мы создадим простую домашнюю страницу без данных. Любой странице обычно нужен URL, представление (view) и шаблон (template). Представление — функция Python, которая принимает HTML-запрос и возвращает ответ на него. Шаблон — специальный набор инструкций, позволяющий динамически генерировать HTML.

Сопоставление URL-адресов проекта

Основной файл проекта urls.py сообщает Django, где найти файлы urls.py , связанные с каждым приложением в проекте.

Сопоставление URL-адресов приложения

Файл urls.py в приложении сообщает Django, какое представление использовать для каждого URL-адреса в этом приложении. Вам нужно создать этот файл самостоятельно и сохранить его в папке приложения.

Создание простого представления

Представление берёт информацию из запроса и отправляет данные в браузер, часто через шаблон. Функции представления хранятся в файле views.py . Ниже приведена простая функция, которая не извлекает какие-либо данные, но использует для отображения домашней страницы шаблон .

Написание простого шаблона

Шаблон устанавливает структуру страницы. Создайте папку с именем templates в директории проекта. Внутри templates создайте ещё одну папку с тем же именем, как у приложения. Здесь должны быть сохранены все файлы шаблонов. Шаблон домашней страницы будет сохранён как learning_logs/templates/learning_logs/ .

Наследование шаблонов

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

Родительский шаблон

Родительский шаблон определяет общие элементы для набора страниц, а также уникальные блоки для отдельных страниц.

Дочерний шаблон

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

Отступы в шаблоне

Отступы в Python обычно отбиваются четырьмя пробелами. В шаблонах вы часто можете встретить отступы в два пробела, потому что вложенность кода как правило более глубокая.

Создание страницы с данными

Большинство страниц в проекте должны показывать данные, относящиеся к текущему пользователю.

Параметры URL

URL-адрес часто принимает параметр, сообщающий ему, к каким данным из базы данных обращаться. Показанный ниже шаблон URL ищет идентификатор конкретной темы и присваивает его параметру topic_id .

Использование данных в представлении

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

Использование данных в шаблоне

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

Django Shell

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

Начать сеанс оболочки

Доступ к данным из проекта

Пользователи и формы

Большинство веб-приложений позволяют посетителям создавать учётные записи. Это позволяет пользователям работать с собственными данными. Некоторые из этих данных могут быть конфиденциальными, а некоторые — общедоступными. Формы Django позволяют пользователям вводить и изменять свои данные.

Учётные записи пользователей

Учётные записи пользователей можно обрабатывать приложением — ниже оно создаётся под названием users . Пользователи должны иметь возможность зарегистрироваться, войти и выйти из аккаунта. Django автоматизирует большую часть этих действий.

Создание приложения users

После создания приложения обязательно добавьте его в INSTALLED_APPS в файле settings.py проекта.

Добавление URL-адресов приложения users

Добавьте эти строки в файл urls.py проекта, чтобы включить в проект URL-адреса приложения users .

Использование форм в Django

Существует несколько способов создания форм и работы с ними. Вы можете использовать установки Django по умолчанию или настроить свои формы. Наиболее простой способ настроить ввод данных, основанных на ваших моделях — использование класса ModelForm. ModelForm автоматически создаёт форму на основе полей модели.

Создание URL для входа, выхода и регистрации

Пользователи смогут войти, выйти и зарегистрироваться на сайте. Создайте новый файл urls.py в папке приложения users .

Шаблон входа

Тег помогает предотвратить CSRF-атаки с помощью форм. Элемент > отображает форму входа по умолчанию в формате абзаца. Элемент с именем next перенаправляет пользователя на домашнюю страницу после успешного входа в систему.

Отображение текущего статуса входа

Вы можете изменить шаблон base.html , чтобы показать, вошёл ли пользователь на сайт в данный момент, и предоставить ссылку на страницы входа и выхода. Django делает объект user доступным для каждого шаблона.

Тег user.is_authenticated позволяет вам показать конкретный контент пользователям в зависимости от того, вошли они в систему или нет. Свойство > приветствует пользователей, которые вошли в систему. Те же, кто не вошёл в систему, увидят ссылки для регистрации или входа.

Шаблон logged_out

Выход из системы по умолчанию отображается с помощью шаблона logged_out.html , который необходимо сохранить в папке users/templates/registration .

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

Шаблон регистрации

Шаблон register.html отображает поля формы регистрации в виде списка тегов

Данные пользователей

У всех пользователей есть данные, которые относятся только к ним. Любая модель, подключенная напрямую к пользователю, нуждается в поле, связывающем экземпляры модели с конкретным пользователем.

Создание темы, принадлежащей пользователю

Чтобы связать данные с пользователем, импортируйте модель User и добавьте её в качестве внешнего ключа в модель данных.

После изменения модели вам нужно будет мигрировать базу данных и установить user ID для каждого существующего пользователя.

Запрос данных для текущего пользователя

Объект запроса имеет атрибут user в своём представлении. Вы можете использовать этот атрибут для получения данных пользователя — их извлекает метод filter() .

Установка URL перенаправления

Декоратор @login_required отправляет неавторизованных пользователей на страницу входа. Добавьте следующую строку в файл settings.py , чтобы Django знал, как найти страницу входа.

Предотвращение случайного доступа

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

Формы для редактирования данных

С Django можно создать форму с существующими данными пользователя и возможностью изменять и сохранять их.

Создание формы с исходными данными

Параметр instance позволяет указать начальные данные для формы.

Изменение данных перед сохранением

Аргумент commit = False позволяет вносить изменения перед записью в базу данных.

Django — отличный фреймворк, и мы привели лишь малую часть базовых операций в нём. Если вы хотите поэкспериментировать с Django на настоящем сервере — попробуйте наши Облачные VPS с готовым шаблоном Django и почасовой оплатой от 37 копеек. После заказа сервера Django будет готов к работе уже через минуту.

Пишите в комментариях, шпаргалки по каким языкам или фреймворкам вы хотели бы видеть в нашем блоге.

Предыдущая часть.

Знать как создавать и обновлять данные в базе данных необходимо. Однако, скорее всего ваше веб-приложение будет выполнять больше запросов на получение данных из базы, чем на добавление их. Мы уже встречали пример того, как получить все записи для определённой модели:

В SQL это выглядело примерно так:

Примечание

Обратите внимание, что Django не выполняет запрос вида SELECT * во время поиска, а перечисляет все поля явно. Это сделано намеренно – SELECT * иногда может работать медленнее, и (что более важно) – перечисление всех полей более соответствует одному из догматов Python: “Явное лучше, чем неявное“.

Что бы больше узнать о догмах Python – введите import this в командной строке Python.

Давайте рассмотрим подробнее каждую часть из строки Publisher.objects.all() :

Первым идёт имя модели, которую мы определили – Publisher . Ничего удивительного – когда мы хотим получить определённые данные, мы используем модель для этих данных.

Далее идёт атрибут objects . Он называется менеджер (manager). Менеджеры будет рассмотрены более подробно далее в нашей книге. Пока что – всё, что вам стоит знать, это то что менеджер занимается всеми данными и операциями уровня “таблица”.

Последним идёт all() . Это метод менеджера object , который возвращает все строки в таблице базы. Хотя объект выглядит как список – на самом деле это Набор Запросов (QuerySet) – объект, который представляет специальный набор строк таблицы. В Приложении С QuerySet рассматривается более подробно. В этой главе мы будем их рассматривать как обычные списки.

Каждый поиск в базе будет соответствовать этому шаблону – мы вызываем метод менеджера, который связан с моделью, к которой нам необходимо применить запрос.

Фильтрация данных

На самом деле – вам очень редко требуется получить все данные из базы. Как правило – вам требуется какая-то определённая выборка из этих данных. С помощью Django API вы можете отфильтровать данные с помощью метода filter() :

Аргумент, переданный filter() , транслируется в соответствующий запрос SQL WHERE . Предыдущий пример можно представить в виде SQL примерно так:

Вы можете передавать несколько аргументов, что бы уточнить выборку фильтра:

Несколько аргументов будут сформированы в SQL запрос с помощью AND :

Обратите внимание, что по умолчанию в запросах используется SQL оператор “=”. Можно выполнить так:

Двойной символ подчёркивания между name и contains , как в Python, используется Django для обозначения чего-то “магического” – в данном случае, __contains указывает на использование оператор LIKE в SQL-запросе:

Имеется большое количество подобных типов запросов, такие как icontains (регистро-зависимый LIKE ), startswith и endswith , range (в SQL – BETWEEN ). Все они описываются в Приложении С.

Получение отдельного объекта

В примерах с filter() практически всё, что он возвращает – это набор объектов, которые могут быть обработаны как Python-список. Однако, иногда лучше получить отдельный объект, а не целый список. Для этого в Django имеется метод get() :

Вместо списка (или QuerySet) – вы получаете отдельный объект. Поэтому вызов, результатом которого будет несколько объектов вызовет ошибку:

Вызов, который не возвращает ни одного объекта – так же вызове ошибку:

Исключение DoesNotExist является атрибутом класса модели – Publisher.DoesNotExist . В вашем приложении вы можете перехватить такие исключения, например так:

Сортировка данных

Как вы могли заметить в предыдущих примерах – объекты возвращаются в произвольном порядке. В самом деле – мы пока не указывали в запросах как мы хотим отсортировать результат, мы просто получали в том виде, в каком их выдавала база данных.

В ваших Django приложениях вы скорее всего захотите выполнять какую-то сортировку, например – в алфавитном порядке. Что бы сделать это – используйте метод order() :

Особой разницы с результатами all() не видно, но теперь наш SQL запрос включается в себя сортировку:

Вы можете выполнять сортировку по любому полю:

Для сортировки по нескольким полям, в которой второе поле будет уточнять результат первого, используйте несколько аргументов к order_by() :

Вы можете использовать обратную ( reverse ) сортировку, добавив символ “ - “:

Хотя такая возможность является очень полезной – использовать её каждый раз может быть неразумным решением. В большинстве случаев вы заранее знаете поля, по которым вы хотели бы выполнять сортировку. В таком случае – вы можете указать сортировку по умолчанию в описании модели Django:

Тут вы встречаетесь с новой концепцией – класс Meta , который является вложенным классом в описании класса Publisher . Вы можете использовать класс Meta в любой модели, что бы какие-то специфичные опции для модели. Полное описание опций Meta есть в Приложении B, а в данный момент нас интересует опция ordering . При её использовании – Django будет использовать сортировку по полю name , пока вы явно не укажете другое с помощью опции order_by() .

Изменение поиска

Вы уже видели как выполнить фильтрацию данных, и как выполнить их сортировку. Часто, конечно, нужно сделать их вместе. В таком случае – вы можете создать “цепочку” из правил, например:

Как вы догадываетесь – в SQL запросе будет применяться и WHERE и ORDER BY :

“Срезы” данных

Часто так же необходимо получить только определённое количество строк. Допустим, у вас есть тысяча издателей в базе данных, но вам необходимо получить только первого. Вы можете выполнить это с помощью обычного в Python способа “срезов” по индексам (slicing):

В виде SQL-запроса это будет выглядеть примерно так:

Также вы можете получить определённый набор данных, используя срез по диапазону индексов:

Что в виде SQL будет выглядеть так:

Помните, что отрицательные срезы не поддерживаются:

Но это можно выполнить с помощью order_by() и обратной сортировкой, например:

Обновление нескольких объектов одним запросом

В статье Django Book: добавление и обновление данных мы уже упоминали, что метод модели save() обновляет все колонки в строке. В зависимости от вашего приложения – вы, возможно, захотите обновить только некоторые из этих колонок.

Например, мы хотим обновить издателя Apress, и изменить имя с ‘ Apress ‘ на ‘ Apress Publishing ‘. Используя метод save() это выглядело бы так:

А в виде SQL-запроса – примерно так:

(в этом примере у издателя Apress его ID – 52 )

В этом примере вы можете увидеть, что save() задаёт все значения всех колонок, а не только колонку name . Если в вашей базе данных остальные колонки могут меняться из-за действий других процессов – то было бы логичнее изменить только ту колонку, которая вам действительно необходима. Что бы реализовать это – используйте метод update() . Например:

В SQL этот способ будет выглядеть более эффективным и не затронет остальные поля:

Метод update() применим к любому набору запросов, т.е. – вы можете изменять любые записи в наборе данных. Например, вот как вы можете изменить колонку с ‘ U.S.A. ‘ на 'USA' для всех издателей:

Метод update() возвращает значение – целое число, указывающее сколько записей было изменено. В данном случае – изменение коснулось 3-х записей.

Django ORM — это инструмент фреймворка Django, который позволяет взаимодействовать с базами данных, используя высокоуровневые методы Python, а не SQL-запросы. Он относится к типу ORM, который реализует шаблон Active Record. Общая суть шаблона в том, что каждой таблице в приложении соответствует одна модель.

В этой статье мы рассмотрим несколько интересных фич Django ORM, которые помогают эффективно управлять данными в проектах Django.

Django ORM

1. Основы Django ORM

Вот пример модели пользователя:

Каждый объект соответствует записи в таблице. ORM отвечает за преобразование табличных данных в объекты и обратно. Разработчику остается только выбирать подходящие методы.

Например, можно найти пользователя по идентификатору:

Или обновить его никнейм:

Изменения сохраняются в базе данных после использования метода save :

Можно посчитать количество пользователей в БД:

Главный плюс Django ORM — существенное упрощение запросов. Это возможно благодаря Query Builder — абстракции поверх SQL.

В Django ORM существует возможность делать SQL-запросы напрямую. Однако это лучше оставить для тех крайних случаев, с которыми Query Builder не справляется.

2. Плюсы и минусы Django ORM

Главные плюсы использования Django ORM — миграция и транзакции.

  1. Можно без труда менять таблицы и обновлять модели. Django автоматически генерирует порядок миграции для внесений изменений в БД.
  2. В рамках одной транзакции можно сделать несколько обновлений БД. Если что-то пойдет не так, всегда остается возможность откатиться к предыдущему состоянию.

Недостатки у Django ORM тоже есть. Главным источником проблем становится чрезмерная простота инструмента. Разработчикам не обязательно знать, какие SQL-запросы генерируются. Из-за этого может значительно увеличиваться нагрузка на сервер.

3. Проверка запросов

Connection.queries

Если в настройках Django-проекта установлен параметр debug = True , то можно смотреть выполненные запросы с помощью connection.queries . Пример:

Shell_plus –print-sql

Shell_plus — одна из функций библиотеки расширений для Django. При вызове с параметром — print-sql она отображает SQL-запросы по мере их выполнения. Например:

Django Silk

Silk — инструмент профилирования Django. Он записывает и визуализирует выполненные SQL-запросы. Это позволяет разработчику видеть, какие запросы отработали, изучать подробности по каждому обращению к БД, в том числе контролировать, какая строка кода инициировала запрос.

Django Debug Toolbar

Debug Toolbar добавляет в браузер отладочную панель. Она предоставляет много возможностей для проверки проекта и исправления ошибок, в том числе отображает выполненные SQL-запросы. Можно проверить каждый запрос, посмотреть порядок их выполнения, а также затраченное время (профилирование).

4. Фильтрация данных

Аргумент filter появился еще в версии Django 2.0. Это заметно упростило получение данных по нескольким условиям. Например, вот так просто можно увидеть общее количество пользователей и общее количество активных пользователей.

Сравните, насколько больше кода нужно написать для решения той же задачи без использования filter :

В PostgreSQL та же операция выглядит следующим образом:

Ничего сложного, но с ORM все равно намного удобнее.

5. QuerySet – результаты в виде именованного кортежа

Еще один полезный атрибут — named . Если он равен True , то QuerySet отображается в виде именованного кортежа:

6. Пользовательские функции ORM Django

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

Например, нужно найти среднюю продолжительность. Сделать это легко:

Но само по себе среднее значение ничего не дает. Допустим, для анализа требуется еще среднеквадратичное отклонение:

Здесь PostgreSQL сообщает об ошибке. Stddev не поддерживается на поле типа interval . Сначала нужно привести interval к числу. Можно сделать это с помощью функции Extract :

То же самое можно реализовать в Django с помощью пользовательских функций:

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

7. Ограничение времени выполнения запроса

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

Например, вот так устанавливается глобальный таймаут:

Используется файл wsgi.py , чтобы ограничить только рабочие процессы.

Таймаут также можно настроить на уровне пользователя:

Еще одна хорошая практика — устанавливать таймаут на вызов удаленной службы, чтобы не ждать бесконечно ответа:

8. Установка лимита

Еще один способ оптимизации запросов — установка лимитов.
Например, пользователю нужно получить список всех продаж с начала работы компании. Разработчик понимает, что такая ситуация может случиться, и поэтому устанавливает лимит: не более 100 записей.

Оператор limit гарантирует, что пользователь получит только 100 записей. Но здесь возникает проблема. Пользователь хотел получить все записи. Получил 100. Он может подумать, что в базе данных всего 100 записей. Но что если это не так? Как об этом сообщить пользователю?

Логичное решение — выбрасывать исключение, если записей больше, чем разрешено лимитом:

Можно сделать еще удобнее.

Вместо того чтобы запрашивать первые 100 записей, код запрашивает 100 + 1 запись. Если есть запись 101, то всего записей уже точно больше 100. Значит, будет выброшено исключение.

9. Использование кэшированных внешних ключей

Если необходимо получить идентификатор внешнего ключа, можно использовать кэшированный ID с помощью _id .
Например, пусть будет такой запрос:

Вот какие SQL-запросы выполняются:

После обращения к id объекта blog создается еще один запрос, который возвращает весь объект blog . Но если не требуется доступ к другим атрибутам объекта blog , то и возвращать его целиком нет смысла.

Использование кэшированного id :

При таком вызове будет на один запрос меньше:

10. Использование select_related

Еще одна хорошая практика — заранее рассказывать Django, что нужно делать. Например, для этого есть функция select_related . Она позволяет точно указать, какие связанные модели потребуются, чтобы Django мог выполнить JOIN .

Например, есть модель Post . Каждый Post принадлежит определенному Blog, а отношения эти выражены в базе данных через внешние ключи.

Допустим, нужно получить определенный Post :

А теперь нужно получить доступ к Blog из Post :

Чтобы получить информацию из Blog , ORM выполнил новый запрос. Этого можно избежать, используя select_related :

Кроме того, что количество запросов уменьшилось, было выполнено кэширование. Дополнительный запрос теперь не нужен. Функция select_related работает также для набора запросов. Не нужно каждый раз обращаться к базе данных, чтобы проверить связь — достаточно сделать это один раз.

11. Индексы внешних ключей

Django создает B-Tree индексы для внешних ключей в модели. Они не всегда нужны и при этом занимают много места. Типичный пример — модель с отношением многие-ко-многим:

Здесь будет два внешних индекса — для user и group .

Еще одна стандартная ситуация — уникальные ограничения. Например, один пользователь может быть членом одной группы только один раз:

Unique_together создает индекс для обоих полей: group и user . В итоге есть одна модель, два поля и целых три индекса.

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

Цель этих манипуляций — оптимизация. Без лишних индексов вставка и обновление данных будут проходить быстрее, а база данных будет весить меньше.

12. Порядок столбцов в составном индексе

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

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

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

13. BRIN-индексы

Основная проблема индексов B-Tree в том, что они занимают много места. Выше мы рассмотрели, как можно их оптимизировать. Но есть и альтернативные способы — например, в PostgreSQL можно использовать BRIN (Block Range Index). В некоторых случаях этот тип индексов эффективнее, чем B-Tree .

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

Фактически BRIN создает мини-индекс, используя ряд соседних блоков в таблице. Каждый такой мини-индекс может сказать, находится определенное значение в диапазоне блоков или нет.

Например, есть девять блоков:

Их можно объединить по три:

Для простоты в каждом диапазоне будет храниться минимальное и максимальное значения:

Например, нужно найти блок 8. Процесс будет выглядеть следующим образом:

[1–3] — здесь такого точно нет;

[4–6] — здесь такого точно нет;

[7–9] — возможно, здесь.

Благодаря такому разделению поиск ограничивается одним диапазоном.

Но все ломается, если значения не отсортированы. Например,

Диапазоны с минимальными и максимальными значениями будут выглядеть так:

Например, нужно найти блок 5.

[2–8] — возможно, здесь;

[3–9] — возможно, здесь;

[1–7] — возможно, здесь.

Разделение на диапазоны становится не только бесполезным, но и вредным. Одну и ту же работу приходится выполнять несколько раз.
Для максимально полезного использования BRIN данные должны быть отсортированы или сгруппированы. Например, можно использовать поле auto_now_add :

Теперь при добавлении данных Django будет автоматически записывать время. Это значит, что можно использовать BRIN -индекс.

При небольшом количестве записей разница в размере БД будет незаметной. Но если добавить в таблицу два миллиона записей и отсортировать их по дате, то разница будет значительная:

B-Tree -индекс — 37 MB

BRIN -индекс — 49 KB

Заключение

В этой статье мы разобрали основы, плюсы и минусы Django ORM, научились проверять запросы, а также познакомились с некоторыми полезными функциями.

Чтобы закрепить материал и узнать еще больше о работе с Django ORM, посмотрите этот часовой видеокурс:

Читайте также: