todos с помощью миграции и реализуете обработку запросов на создание, чтение, обновление и удаление в небольшом JSON-представлении. Все соединения защищены TLS с полной проверкой сертификатов.
Предварительные требования
- Python 3.12 или новее (этого требует Django 6). Руководство проверено на Python 3.13, Django 6.1.1 и psycopg 3.3.6.
- Аккаунт ClickHouse Cloud
psqlдля создания базы данных. Также можно выполнить операторCREATE DATABASEв консоли SQL.
Создание сервиса ClickHouse Managed Postgres
В консоли ClickHouse Cloud нажмите New service и выберите Postgres. Инстанс будет готов через несколько минут. Пошаговые инструкции приведены в кратком руководстве по началу работы.Получение сведений о подключении
Нажмите Connect на левой боковой панели вашего сервиса. В открывшемся модальном окне отображаются имя пользователя, пароль, сервер и порт, а также переключатель Directly / via PgBouncer. В этом руководстве Django подключается через встроенный PgBouncer на порту6432. В продакшне приложение Django обычно работает в виде нескольких воркер-процессов на нескольких машинах, и каждый из них открывает собственные соединения. PgBouncer работает в режиме пулинга транзакций (transaction pooling) и позволяет всем этим процессам совместно использовать небольшое число соединений с Postgres. Для работы с пулингом транзакций Django нужно несколько настроек — они приведены и описаны в разделе Настройки PgBouncer для Django.
Выберите via PgBouncer, чтобы увидеть сведения о подключении через пул. Порт изменится на 6432, а строка подключения будет содержать sslmode=verify-full.
В модальном окне нажмите Download CA‑сертификат. Сертификат также можно скачать в разделе Settings → CA‑сертификат. Он уникален для вашего инстанса, поэтому драйвер может с его помощью убедиться, что подключается именно к вашему серверу.
Настройка проекта
Создайте каталог проекта с виртуальным окружением, установите Django и psycopg 3, а затем создайте проект Django с приложениемtodos:
psycopg[binary] включает актуальную версию libpq, поэтому устанавливать PostgreSQL локально не нужно.
Настройка соединения
Переместите загруженный CA‑сертификат в каталог проекта (рядом сmanage.py) и переименуйте его в ca-certificate.pem.
Создайте базу данных для приложения. Замените <PASSWORD> и хост значениями из модального окна Connect:
mysite/settings.py, добавьте import os после строки from pathlib import Path и замените параметр DATABASES следующим кодом:
mysite/settings.py
OPTIONS в psycopg, а тот — в libpq. Если для sslmode задано значение verify-full, libpq проверяет, что сертификат сервера подписан CA вашего сервиса и соответствует имени хоста. BASE_DIR делает путь к сертификату абсолютным, поэтому настройка работает независимо от того, из какого каталога запускается Django.
Если
sslrootcert указывает на неверный CA, установить соединение не удастся: возникнет ошибка SSL error: certificate verify failed. Без sslrootcert возникает ошибка root certificate file ".../.postgresql/root.crt" does not exist, поскольку libpq в этом случае ищет CA в расположении по умолчанию. Если подключаться по IP-адресу, а не по имени хоста, возникает ошибка server certificate for "..." does not match host name.Создайте модель и выполните миграции
Добавьте приложениеtodos в INSTALLED_APPS в файле mysite/settings.py:
mysite/settings.py
Todo в файле todos/models.py:
todos/models.py
todos_todo, команда migrate создаёт таблицы для встроенных приложений Django, таких как auth_user и django_session, а также записывает применённые миграции в django_migrations. Если у вас уже есть приложение, пропустите создание модели todos и выполните только python manage.py migrate — эта команда создаст все таблицы вашего приложения в новой базе данных.
migrate не захватывает рекомендательную блокировку (advisory lock) уровня сеанса, поэтому работает через PgBouncer. При этом она не защищает от одновременных запусков, поэтому выполняйте миграции только из одного места, например на отдельном шаге развёртывания.
Добавление конечной точки JSON
Замените содержимоеtodos/views.py двумя представлениями, которые создают, выводят, обновляют и удаляют задачи с помощью Django ORM:
todos/views.py
mysite/urls.py, чтобы маршрутизировать /todos и /todos/<id> в представления:
mysite/urls.py
Запуск и проверка
Запустите сервер для разработки:PATCH возвращает обновлённую строку:
http://localhost:3111/todos, чтобы просмотреть список оставшихся задач. Ответ будет выглядеть так:
guide_django, затем public и выберите таблицу todos_todo. В таблице осталась одна строка:
Настройки PgBouncer для Django
PgBouncer работает в режиме пулинга транзакций (пулинг транзакций): каждая транзакция или каждый оператор вне транзакции может выполняться на другом соединении с Postgres. Ниже описано, как это влияет на приведённые выше настройки и другие возможности Django:DISABLE_SERVER_SIDE_CURSORS:QuerySet.iteratorчитает строки фрагментами через серверный курсор. Вне транзакции Django объявляет курсор какWITH HOLDи получает каждый фрагмент отдельно, поэтому при работе через PgBouncer очередной запрос фрагмента может попасть на соединение с Postgres, в котором этого курсора нет, и завершиться ошибкойcursor "_django_curs_..." does not exist. Это происходит, только когда пулом одновременно пользуются другие клиенты, поэтому при разработке проблема часто не проявляется. Если настройка включена,.iterator()использует обычный курсор, и psycopg загружает весь результат в память. Чтобы потоково обработать очень большую таблицу, выполняйте такой код через прямое соединение на порту5432с отключённой настройкой.CONN_MAX_AGE: по умолчанию (0) Django открывает новое соединение для каждого запроса. Установка TLS‑соединения требует нескольких сетевых обменов — как через PgBouncer, так и напрямую, — поэтому повторное использование соединений значительно ускоряет обработку запросов. В тесте с ноутбука с четырьмя воркерами Gunicorn значениеCONN_MAX_AGE, равное600, сократило медианное время запроса примерно с 670 мс до 95 мс. При работе через PgBouncer открытое соединение Django не удерживает соединение с Postgres между транзакциями, поэтому постоянные соединения не расходуют лимитmax_connections.CONN_HEALTH_CHECKSзаставляет Django проверять повторно используемое соединение в начале каждого запроса и переподключаться, если оно было закрыто.- Пул соединений: встроенный пул Django (
"pool": TrueвOPTIONS, для которого требуетсяpip install "psycopg[binary,pool]") даёт сопоставимое ускорение и также работает через PgBouncer. Он требует значенияCONN_MAX_AGE, равного0, и держит открытыми не менее четырёх соединений на процесс. С PgBouncer большинству приложений достаточноCONN_MAX_AGE; пул имеет смысл рассмотреть для многопоточных или ASGI‑серверов. - Подготовленные операторы: настройка не требуется. По умолчанию Django устанавливает параметр psycopg
prepare_thresholdвNoneи привязывает параметры запроса на стороне клиента, поэтому серверные подготовленные операторы не создаются. Если включить"server_side_binding": Trueи задать"prepare_threshold"вOPTIONS, подготовленные операторы также будут работать через PgBouncer, посколькуpsycopg[binary]поставляется сlibpq18 и освобождает операторы с помощью сообщения протоколаClose. Если psycopg собран сlibpqверсии 16 или более ранней, освобождение оператора внутри транзакции завершается ошибкойprepared statement "_pg3_0" does not exist. Чтобы проверить версию, выполнитеpython -c "import psycopg; print(psycopg.pq.version())". Требуется170000или выше. - Состояние сеанса: оператор
SET, напримерSET search_path, применяется только к соединению с Postgres, в котором он был выполнен, поэтому последующие запросы могут его не увидеть, а запросы других клиентов — наоборот, увидеть. PgBouncer отклоняет настройку Django"options": "-c search_path=..."с ошибкойunsupported startup parameter in options: search_path. Вместо этого задавайте значения по умолчанию на уровне базы данных, например с помощьюALTER DATABASE guide_django SET search_path = myschema, public;. Не используйте параметрassume_role, который выполняетSET ROLE. Встроенная обработкаTIME_ZONEв Django и параметрisolation_levelработают через PgBouncer.
PORT в 5432 и удалите DISABLE_SERVER_SIDE_CURSORS. В этом случае каждый воркер Django удерживает собственное соединение с Postgres, поэтому общее число воркеров должно быть меньше max_connections.
Дальнейшие шаги
- Подключение: строки подключения, PgBouncer и TLS
- Настройки: параметры Postgres и PgBouncer, например
max_connections - Реплики для чтения: направление запросов на чтение в реплику с помощью поддержки нескольких баз данных в Django
- Безопасность: IP Access List и частное сетевое подключение