Всё это время мы работали с SQLite — файловой базой данных, которая идеальна для разработки: не требует установки, не нужно настраивать подключение, вся база в одном файле. Но у SQLite есть принципиальные ограничения:
- Конкурентная запись — SQLite блокирует весь файл на запись. При нескольких одновременных запросах они выстраиваются в очередь. На продакшне с реальной нагрузкой это узкое место.
- Нет сетевого доступа — SQLite это файл на диске. Несколько серверов приложения не могут работать с одной базой одновременно.
- Ограниченный SQL — PostgreSQL поддерживает полнотекстовый поиск, JSON-поля, оконные функции и многое другое, чего нет в SQLite.
PostgreSQL — стандарт индустрии для Django-проектов на продакшне. Сегодня переводим проект на него и переносим данные.
Прежде чем менять базу данных, нужно сохранить всё, что уже есть в SQLite. Для этого Django предоставляет fixtures — механизм сериализации данных из БД в JSON (или XML/YAML), который затем можно загрузить в любую базу.
python manage.py dumpdata --output=db_backup.json --indent=2Это выгрузит все данные из всех таблиц. Но стандартные таблицы Django (сессии, типы контента, логи) при загрузке в новую БД могут создать конфликты. Лучше выгружать только нужные приложения:
Если вы работаете на Windows и при загрузке фикстуры возникают ошибки кодировки, используйте следующую команду:
python -Xutf8 manage.py dumpdata --output=db_backup.json --indent=2Флаг -Xutf8 запускает Python в режиме UTF-8 независимо от региональных настроек Windows.
# Выгрузить только данные приложения films
python manage.py dumpdata films --output=films_data.json --indent=2
# для Windows
python -Xutf8 manage.py dumpdata films --output=films_data.json --indent=2
# Выгрузить пользователей и группы
python manage.py dumpdata auth.user auth.group --output=users_data.json --indent=2
# для Windows
python -Xutf8 manage.py dumpdata auth.user auth.group --output=users_data.json --indent=2Посмотрим на структуру файла:
[
{
"model": "films.genre",
"pk": 1,
"fields": {
"name": "Драма",
"slug": "drama"
}
},
{
"model": "films.film",
"pk": 1,
"fields": {
"title": "Крёстный отец",
"year": 1972,
"slug": "krestnyj-otec",
"rating": "9.2",
"director": 1
}
}
]Каждый объект описывается тремя ключами: model (приложение.модель), pk (первичный ключ), fields (значения полей).
python manage.py dumpdata \
--exclude=contenttypes \
--exclude=auth.permission \
--exclude=sessions \
--output=full_backup.json \
--indent=2для Windows PowerShell:
python -Xutf8 manage.py dumpdata `
--exclude=contenttypes `
--exclude=auth.permission `
--exclude=sessions `
--output=full_backup.json `
--indent=2contenttypes и auth.permission создаются автоматически при migrate на основе установленных приложений — загрузка их из фикстуры часто вызывает конфликты. Исключаем их и даём Django создать заново.
Сначала необходимо установить сам PostgreSQL. Способ установки зависит от вашей операционной системы.
macOS:
Если вы используете Homebrew, установите PostgreSQL следующей командой:
brew install postgresql@16После установки запустите PostgreSQL как фоновый сервис:
brew services start postgresql@16После этого PostgreSQL будет запущен, и с ним можно будет работать через терминал.
Ubuntu/Debian:
Установите PostgreSQL:
sudo apt install postgresql postgresql-contribЗапустите сервер PostgreSQL:
sudo systemctl start postgresqlЧтобы PostgreSQL автоматически запускался вместе с операционной системой:
sudo systemctl enable postgresqlWindows:
Скачайте установщик PostgreSQL с официального сайта: https://www.postgresql.org/download/windows/. Запустите установщик и пройдите стандартную процедуру установки.
Во время установки вам будет предложено задать пароль пользователя postgres. Обязательно запомните этот пароль — он понадобится для подключения к PostgreSQL с правами администратора.
После установки PostgreSQL в Windows обычно уже запущен как системная служба, поэтому вручную запускать сервер, как на Linux или macOS, чаще всего не требуется.
После установки нам необходимо настроить переменную среды PATH. Это позволит запускать команду psql из PowerShell или командной строки Windows, находясь в любой директории.
Во время установки PostgreSQL исполняемые файлы PostgreSQL помещаются в папку bin. Обычно она находится примерно здесь:
C:\Program Files\PostgreSQL\16\bin
Номер версии может отличаться (16, 17, 18).
Далее нужно добавить эту папку в PATH.
Выполните следующие действия:
Шаг 1.
Откройте меню «Пуск» и введите в поиске Переменные среды.
Выберите пункт: «Изменение системных переменных среды».
Откроется окно «Свойства системы».
Шаг 2.
Нажмите кнопку: «Переменные среды...»
Шаг 3.
В верхней части окна найдите раздел «Переменные среды пользователя».
Выберите переменную Path и нажмите: «Изменить...»
Шаг 4.
Нажмите: «Создать»
и добавьте путь к папке bin (прим. C:\Program Files\PostgreSQL\16\bin) вашей установки PostgreSQL.
Подтвердите изменения кнопками «ОК».
Если PowerShell был открыт во время изменения PATH, закройте его и откройте заново. Теперь команда psql должна быть доступна из любой директории. Проверить это можно следующей командой:
psql --versionЕсли всё настроено правильно, вы увидите установленную версию PostgreSQL, например: psql (PostgreSQL) 16.x.
Теперь вы можете запускать psql непосредственно из PowerShell, находясь в любой директории.
После установки PostgreSQL нам необходимо создать отдельного пользователя и базу данных для нашего Django-проекта. В PostgreSQL существует стандартный административный пользователь postgres. Сначала необходимо подключиться к PostgreSQL от его имени. Способ подключения зависит от операционной системы.
macOS с Homebrew:
Откройте терминал и выполните:
psql postgresЕсли команда выполняется успешно, вы попадёте в интерактивную консоль PostgreSQL:
postgres=#
Ubuntu/Debian:
Откройте терминал и выполните:
sudo -u postgres psqlПосле успешного подключения вы также увидите:
postgres=#
Windows через PowerShell:
Благодаря тому, что мы добавили PostgreSQL в PATH, теперь можно открыть PowerShell в любой директории и выполнить:
psql -U postgres -d postgresПосле этого PostgreSQL попросит ввести пароль:
Password for user postgres:
Введите пароль пользователя postgres, который был задан во время установки PostgreSQL. Если подключение прошло успешно, появится приглашение:
postgres=#
Важно: при вводе пароля символы не отображаются на экране. Это нормальное поведение. Просто введите пароль и нажмите
Enter.
Теперь мы находимся внутри консоли PostgreSQL. Это можно определить по приглашению:
postgres=#
Все следующие команды необходимо выполнять внутри psql, а не в PowerShell, CMD или обычном терминале.
Создадим отдельного пользователя для нашего Django-проекта:
CREATE USER filmsite_user WITH PASSWORD 'ваш_надёжный_пароль';Создадим базу данных и сразу назначим filmsite_user её владельцем:
CREATE DATABASE filmsite_db OWNER filmsite_user;Теперь подключимся к созданной базе данных:
\c filmsite_dbПосле выполнения этой команды приглашение должно измениться примерно на:
filmsite_db=#
Теперь необходимо предоставить пользователю права на схему public.
GRANT ALL ON SCHEMA public TO filmsite_user;Эта команда важна для Django. Во время выполнения миграций Django должен создавать и изменять таблицы, индексы и другие объекты базы данных. Для этого пользователь, под которым Django подключается к PostgreSQL, должен иметь необходимые права на схему, в которой будут находиться эти объекты.
Таким образом, Django сможет выполнять стандартные операции с базой данных, необходимые для работы проекта.
После этого выйдите из консоли PostgreSQL:
\qТеперь у нас есть:
- пользователь PostgreSQL:
filmsite_user; - база данных:
filmsite_db; - пароль: тот, который был указан при создании пользователя;
- пользователь
filmsite_userявляется владельцем базы данных; - пользователь
filmsite_userимеет необходимые права на схемуpublic.
После настройки подключения Django сможет выполнить миграции и создать необходимые таблицы проекта.
psycopg2 — это специальная библиотека, которая позволяет Python работать с базой данных PostgreSQL. Сам Django не умеет напрямую отправлять SQL-запросы в PostgreSQL.
Когда вы вызываете, например Film.objects.all(), Django строит SQL-запрос, а затем передаёт его библиотеке psycopg2. Она устанавливает соединение с PostgreSQL, отправляет запрос серверу базы данных, получает результат и возвращает его обратно Django.
psycopg2 часто называют адаптером — он выступает посредником между Python и PostgreSQL.
Существует две основные версии этой библиотеки:
psycopg2-binary— библиотека устанавливается сразу и не требует дополнительной настройки системы;psycopg2— этот пакет содержит исходный код библиотеки. Во время установки он компилируется непосредственно на вашем компьютере.
Предварительно собранные бинарные файлы (psycopg2-binary) отлично подходят для разработки: они устанавливаются буквально одной командой и позволяют сразу начать работу.
Однако на боевых серверах чаще используют обычный psycopg2, который собирается непосредственно под конкретную операционную систему и установленную версию PostgreSQL. Такой вариант считается более надёжным и рекомендуется разработчиками библиотеки для production-окружения.
Во время обучения мы будем использовать:
pip install psycopg2-binary# filmsite/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'filmsite_db',
'USER': 'filmsite_user',
'PASSWORD': 'ваш_надёжный_пароль',
'HOST': 'localhost',
'PORT': '5432',
}
}| Параметр | Значение | Назначение |
|---|---|---|
ENGINE |
postgresql |
Использовать PostgreSQL-бэкенд |
NAME |
имя БД | База данных, созданная выше |
USER |
пользователь БД | Пользователь PostgreSQL |
PASSWORD |
пароль | Пароль пользователя PostgreSQL |
HOST |
localhost |
Сервер БД (на продакшне — IP или hostname) |
PORT |
5432 |
Стандартный порт PostgreSQL |
Как и с SMTP в уроке 25 — не храним учётные данные прямо в settings.py:
# filmsite/settings.py
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME', 'filmsite_db'),
'USER': os.environ.get('DB_USER', 'filmsite_user'),
'PASSWORD': os.environ.get('DB_PASSWORD', ''),
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': os.environ.get('DB_PORT', '5432'),
}
}PostgreSQL подключён, но таблиц в ней ещё нет:
python manage.py migrateDjango создаст все таблицы заново по существующим файлам миграций. База чистая — данных нет.
# Загружаем пользователей
python manage.py loaddata users_data.json
# Загружаем данные приложения
python manage.py loaddata films_data.jsonloaddata читает JSON-файл и создаёт объекты в базе данных. Порядок загрузки имеет значение: если в films_data.json есть записи Film со ссылками на Director по pk, то Director должен быть загружен раньше. Если выгрузить все данные приложения films одной командой — Django сам сохранит правильный порядок.
python manage.py shellfrom films.models import Film, Genre, Director
print(f'Фильмов: {Film.objects.count()}')
print(f'Жанров: {Genre.objects.count()}')
print(f'Режиссёров: {Director.objects.count()}')Fixtures полезны не только для миграции — это стандартный способ хранить начальные данные для тестов и для быстрого наполнения базы при разворачивании на новом сервере.
# Создать фикстуру с тестовыми жанрами
python manage.py dumpdata films.genre \
--output=films/fixtures/genres.json \
--indent=2для Windows PowerShell:
# Создать фикстуру с тестовыми жанрами
python -Xutf8 manage.py dumpdata films.genre `
--output=films/fixtures/genres.json `
--indent=2Django ищет fixtures в папке fixtures/ каждого приложения — если там лежат файлы, их можно загрузить без указания пути:
python manage.py loaddata genres.jsonЭто удобно для автоматического заполнения базы при разворачивании проекта: добавить вызов loaddata в скрипт деплоя или Makefile.
Хорошая новость: практически ничего. Django ORM абстрагирует различия между базами данных. QuerySet'ы, фильтры, аннотации — всё работает одинаково. Несколько отличий, которые стоит знать:
Чувствительность к регистру. SQLite нечувствителен к регистру в строках. PostgreSQL — чувствителен. Если где-то использовался filter(title='крёстный отец') вместо filter(title__iexact='крёстный отец') — в PostgreSQL это даст пустой результат. Везде в нашем коде мы использовали icontains и iexact — это корректная практика, которая работает одинаково в обеих базах.
Строгие типы. PostgreSQL строго проверяет типы: нельзя вставить строку в числовое поле. SQLite был более снисходителен. Если в данных были «грязные» значения — PostgreSQL может отказать при загрузке.
Полнотекстовый поиск. PostgreSQL поддерживает SearchVector и SearchQuery из django.contrib.postgres.search — это настоящий полнотекстовый поиск с рангированием, а не просто LIKE '%...%'. Для нашего каталога это было бы заметное улучшение, но выходит за рамки базового курса.
Если в PostgreSQL уже есть данные (например, суперпользователь из createsuperuser) и загружается фикстура с теми же pk — возникнет конфликт:
django.db.utils.IntegrityError: duplicate key value violates unique constraint
Решение: загружать данные в абсолютно чистую базу (после migrate, до создания суперпользователя), либо исключать конфликтующие модели из фикстуры.
PostgreSQL использует sequences для автоинкремента id. После загрузки данных через loaddata sequence может не знать о максимальном pk из фикстуры и начать новые записи с id=1, что вызовет конфликт при следующем сохранении. Исправляется командой:
python manage.py sqlsequencereset films | python manage.py dbshellsqlsequencereset генерирует SQL для сброса последовательностей по текущим максимальным значениям id в таблицах.
Иногда старые миграции содержат конструкции, специфичные для SQLite. PostgreSQL строже к типам и может отказать при их применении. Это редкий случай для проектов, которые изначально проектировались корректно (как наш), но важно иметь это в виду при работе с чужим кодом.
- Что такое fixture в Django и для каких задач он используется?
- Почему при выгрузке данных рекомендуется исключать
contenttypesиauth.permission? - Зачем нужен
psycopg2и чем отличаетсяpsycopg2-binaryотpsycopg2? - Почему после
loaddataв PostgreSQL иногда нужно запускатьsqlsequencereset? - Что изменится в поведении
filter()при переходе с SQLite на PostgreSQL?
Тип: расширь проект
Выполни полный цикл переноса данных с SQLite на PostgreSQL.
Шаги:
- Выгрузи данные из SQLite:
films_data.json(приложениеfilms) иusers_data.json(auth.user,auth.group). При выгрузке исключиcontenttypesиauth.permission - Установи PostgreSQL и
psycopg2-binary, создай базу данныхfilmsite_dbи пользователяfilmsite_user - Обнови
DATABASESвsettings.py— вынеси учётные данные в переменные окружения - Примени миграции командой
migrate - Загрузи данные через
loaddata— сначалаfilms_data.json, потомusers_data.json - Запусти сервер и проверь, что каталог фильмов отображается корректно
- Если появились ошибки последовательностей — запусти
sqlsequencereset
Шпаргалка по работе с PostgreSQL через терминал
Подключаемся под пользователем postgres:
psql -U postgresПосле успешного подключения приглашение терминала изменится:
postgres=#
CREATE USER filmsite_user WITH PASSWORD 'MyStrongPassword123!';CREATE DATABASE filmsite_db OWNER filmsite_user;GRANT ALL PRIVILEGES ON DATABASE filmsite_db TO filmsite_user;\duПример:
Role name | Attributes
----------------+-------------------------------------
postgres | Superuser, Create role, Create DB
filmsite_user |
\lили
\listЕсли вы уже находитесь внутри PostgreSQL:
\c filmsite_db filmsite_userили
\connect filmsite_db filmsite_userПосле подключения приглашение изменится:
filmsite_db=>
Теперь все запросы будут выполняться именно в этой базе данных.
\dtЕсли таблиц много:
\dt *Например:
\d users_customuserили
\d auth_userБудут показаны:
- поля;
- типы данных;
- ограничения;
- индексы;
- внешние ключи.
Например:
SELECT * FROM auth_user;или
SELECT * FROM users_customuser;SELECT * FROM auth_user
LIMIT 10;SELECT id, username, email
FROM auth_user;Например:
SELECT *
FROM auth_user
WHERE id = 1;или
SELECT *
FROM auth_user
WHERE username = 'admin';SELECT *
FROM auth_user
ORDER BY id DESC;SELECT COUNT(*)
FROM auth_user;Например:
DELETE FROM auth_user
WHERE id = 5;
⚠️ Будьте осторожны! После выполнения запроса запись будет удалена.
TRUNCATE TABLE auth_user;Если таблица связана внешними ключами:
TRUNCATE TABLE auth_user RESTART IDENTITY CASCADE;RESTART IDENTITY— сбрасывает счётчикиid;CASCADE— очищает связанные таблицы.
SELECT current_user;SELECT current_database();\dn\dsНапример:
\i backup.sqlВернуться в базу postgres:
\c postgres\q| Команда | Назначение |
|---|---|
\l |
Список баз данных |
\c имя_базы |
Подключиться к базе |
\dt |
Список таблиц |
\d таблица |
Структура таблицы |
\du |
Список пользователей |
\dn |
Список схем |
\ds |
Список последовательностей |
\q |
Выход из PostgreSQL |
Можно подключиться сразу к нужной базе, не заходя под postgres:
psql -U filmsite_user -d filmsite_dbПосле ввода пароля откроется соединение:
filmsite_db=>
Это наиболее распространённый способ работы с PostgreSQL в повседневной разработке.
Если необходимо полностью начать работу заново, можно удалить все созданные базы данных и пользователей, оставив только стандартного пользователя postgres.
⚠️ Внимание! Все данные будут безвозвратно удалены.
Подключиться под пользователем postgres
psql -U postgresПосмотреть существующие базы данных:
\lНапример:
postgres
filmsite_db
shop_db
test_db
postgres — это системная база данных. Её удалять не нужно.
Удалить созданные базы данных:
Если к базе подключены пользователи, сначала необходимо разорвать все активные соединения:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'filmsite_db'
AND pid <> pg_backend_pid();После этого можно удалить базу:
DROP DATABASE filmsite_db;Аналогично удаляются остальные базы данных:
DROP DATABASE shop_db;
DROP DATABASE test_db;Посмотреть существующих пользователей:
\duНапример:
postgres
filmsite_user
shop_user
test_user
Удалить созданных пользователей:
DROP ROLE filmsite_user;
DROP ROLE shop_user;
DROP ROLE test_user;или
DROP USER filmsite_user;
DROP USER shop_user;
DROP USER test_user;
DROP ROLEиDROP USERв PostgreSQL являются эквивалентными командами.
Теперь PostgreSQL находится практически в исходном состоянии и можно заново создавать пользователей, базы данных и выполнять миграции Django.