Базы данных в Django: настройка DATABASES и SQLite
Как Django работает с базой данных: поддерживаемые СУБД, настройка DATABASES, SQLite по умолчанию, dbshell, сырой SQL без инъекций и несколько баз.
Содержание · 10 разделов
- Какие базы данных поддерживает Django
- Настройка DATABASES в settings.py
- SQLite в Django по умолчанию
- Когда SQLite хватает
- Особенности SQLite, которые удивляют
- Настройка SQLite для продакшна
- dbshell: консоль базы данных
- Сырой SQL в Django
- Как посмотреть SQL, который генерирует ORM
- Manager.raw(): SQL-запрос с моделями на выходе
- connection.cursor(): SQL без моделей
- Защита от SQL-инъекций
- Несколько баз данных и роутеры
- Роутер базы данных
- Параметры подключения в переменных окружения
- Частые ошибки
- Частые вопросы
- Нужно ли добавлять db.sqlite3 в git?
- Как очистить базу, не удаляя таблицы?
- Как подключить Django к существующей базе с готовыми таблицами?
- Можно ли разрабатывать на SQLite, а в продакшне использовать PostgreSQL?
- Как перенести данные из SQLite в PostgreSQL или MySQL?
- Чем raw() отличается от connection.cursor()?
- Итог
База данных в Django подключается одной настройкой — словарём DATABASES в settings.py. Новый проект сразу работает с SQLite: данные лежат в файле db.sqlite3, драйвер входит в состав Python, ставить ничего не нужно. Чтобы перейти на PostgreSQL, MySQL или другую СУБД, меняют ENGINE и параметры подключения, устанавливают драйвер и выполняют python manage.py migrate.
# config/settings.py — так настройку создаёт startproject
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
Ниже — какие СУБД поддерживает Django, из чего состоит DATABASES, когда хватает SQLite, как открыть консоль базы через dbshell, как выполнять сырой SQL без риска инъекций и как подключить несколько баз. Примеры проверены на Django 6.1 и Python 3.12.
Какие базы данных поддерживает Django
Django из коробки работает с пятью СУБД. Минимальные версии растут с каждым релизом Django, поэтому перед обновлением фреймворка проверьте версию сервера базы.
| СУБД | Значение ENGINE | Драйвер (Django 6.1) | Django 6.1 | Django 5.2 LTS |
|---|---|---|---|---|
| PostgreSQL | django.db.backends.postgresql | psycopg 3.1.12+ или psycopg2 2.9.9+ | 15 и новее | 14 и новее |
| MariaDB | django.db.backends.mysql | mysqlclient 2.2.1+ | 10.11 и новее | 10.5 и новее |
| MySQL | django.db.backends.mysql | mysqlclient 2.2.1+ | 8.4 и новее | 8.0.11 и новее |
| SQLite | django.db.backends.sqlite3 | модуль sqlite3 из стандартной библиотеки | 3.37.0 и новее | 3.31.0 и новее |
| Oracle | django.db.backends.oracle | oracledb 2.3.0+ | 19c и новее | 19c и новее |
MariaDB использует тот же движок, что и MySQL. Для остальных СУБД есть сторонние бэкенды: Microsoft SQL Server (mssql-django), MongoDB (django-mongodb-backend), CockroachDB, YugabyteDB, TiDB, Google Cloud Spanner, Snowflake и Firebird. Их поддерживают отдельные команды, и набор возможностей ORM у них заметно отличается — проверяйте совместимость с вашей версией Django до выбора.
Как выбрать:
- SQLite — обучение, прототипы, тесты, небольшие сайты на одном сервере, где запросов на чтение намного больше, чем на запись.
- PostgreSQL — выбор по умолчанию для продакшна: параллельная запись,
JSONFieldс поиском по ключам, полнотекстовый поиск иArrayFieldизdjango.contrib.postgres. Пошаговая настройка — в статье «Как подключить PostgreSQL к Django». - MySQL и MariaDB — когда хостинг или инфраструктура компании уже дают эту СУБД. Подключение разобрано в статье «Как подключить MySQL к Django».
- Oracle и SQL Server — корпоративные системы, где база уже есть и выбирать не приходится.
Настройка DATABASES в settings.py
DATABASES — словарь, где ключ — псевдоним базы (alias), а значение — параметры подключения. Псевдоним default обязателен: его Django использует, когда база не указана явно. Остальные псевдонимы нужны только при работе с несколькими базами.
Типичная настройка для сервера СУБД:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "mysite",
"USER": "mysite",
"PASSWORD": "пароль",
"HOST": "127.0.0.1",
"PORT": "5432",
}
}
Основные ключи:
| Ключ | По умолчанию | Что задаёт |
|---|---|---|
ENGINE | — | Бэкенд базы: путь к модулю вроде django.db.backends.postgresql |
NAME | '' | Имя базы; для SQLite — полный путь к файлу |
USER, PASSWORD | '' | Учётные данные; для SQLite не используются |
HOST, PORT | '' | Адрес и порт сервера; пустая строка — localhost и стандартный порт |
OPTIONS | {} | Параметры драйвера: таймауты, SSL, пул соединений, PRAGMA для SQLite |
CONN_MAX_AGE | 0 | Сколько секунд держать соединение открытым; 0 — закрывать после каждого запроса |
CONN_HEALTH_CHECKS | False | Проверять переиспользуемое соединение перед запросом |
ATOMIC_REQUESTS | False | Оборачивать каждое представление (view) в транзакцию |
TEST | {} | Настройки тестовой базы: имя, кодировка, нужно ли применять миграции |
Для SQLite в NAME указывают путь к файлу. Если пишете путь строкой, используйте прямые слэши и на Windows: C:/projects/mysite/db.sqlite3. Удобнее строить путь от BASE_DIR, как в шаблоне проекта, — тогда настройка работает на любой машине.
Остальные ключи Django заполняет значениями по умолчанию. Итоговую конфигурацию показывает команда diffsettings:
python manage.py diffsettings | grep DATABASES
На Windows в PowerShell вместо grep используйте findstr DATABASES.
После изменения настроек создайте таблицы в новой базе командой python manage.py migrate — подробнее о ней в статье «Миграции в Django». Если ENGINE указан с опечаткой, Django сразу перечислит доступные встроенные бэкенды:
django.core.exceptions.ImproperlyConfigured: 'django.db.backends.sqlite' isn't an available database backend or couldn't be imported. Check the above exception. To use one of the built-in backends, use 'django.db.backends.XXX', where XXX is one of:
'mysql', 'oracle', 'postgresql', 'sqlite3'
Важно:
settings.py— обычный Python-файл. ЕслиDATABASESприсваивается в нём дважды (например, второй раз в конце файла или в импортированномlocal_settings.py), действует последнее присваивание.
SQLite в Django по умолчанию
SQLite — встраиваемая СУБД: вся база хранится в одном файле, отдельный сервер не нужен. Модуль sqlite3 входит в стандартную библиотеку Python, поэтому проект после startproject работает без установки драйверов. Как создать проект и где появляется файл базы, описано в статье про django-admin startproject.
Файл db.sqlite3 создаётся при первом обращении к базе — обычно при первом migrate:
python manage.py migrate
Чтобы начать с чистой базы во время разработки, удалите db.sqlite3 и снова выполните migrate. Все данные, включая суперпользователя, пропадут.
Когда SQLite хватает
SQLite подходит, если:
- вы учитесь, делаете прототип или пет-проект;
- сайт работает на одном сервере и в основном читает данные: блог, документация, лендинг с формой обратной связи;
- это внутренний инструмент на несколько пользователей;
- нужна быстрая тестовая база: при запуске тестов на SQLite Django по умолчанию создаёт её в памяти.
Пора переходить на PostgreSQL или MySQL, если:
- одновременно пишут много пользователей и в логах появляется
OperationalError: database is locked; - приложение работает в нескольких контейнерах или на нескольких серверах — общий файл базы между ними не разделить;
- нужны блокировки строк:
select_for_update()на SQLite ничего не делает; - нужны возможности конкретной СУБД:
ArrayField, полнотекстовый поиск PostgreSQL, точная десятичная арифметика.
Особенности SQLite, которые удивляют
Регистр кириллицы. SQLite сравнивает без учёта регистра только латиницу. Поэтому icontains и iexact с русским текстом ведут себя как чувствительные к регистру, а contains для латиницы, наоборот, регистр игнорирует:
# В базе есть книги «Изучаем Python» и «Чистый код»
Book.objects.filter(title__icontains="изучаем").count() # → 0
Book.objects.filter(title__iexact="чистый код").count() # → 0
Book.objects.filter(title__contains="PYTHON").count() # → 1
На PostgreSQL с локалью вроде ru_RU.UTF-8 или en_US.UTF-8 первые два запроса найдут по одной книге. Если сайт ищет по русскому тексту, разрабатывайте сразу на той СУБД, что будет в продакшне.
Десятичные числа. В SQLite нет настоящего десятичного типа: значения DecimalField хранятся как числа с плавающей точкой (REAL), и арифметика в SQL-запросах может давать погрешность округления.
Внешние ключи Django включает сам (PRAGMA foreign_keys), отдельно настраивать их не нужно.
Настройка SQLite для продакшна
Если небольшой сайт работает на SQLite в продакшне, настройте журнал WAL и режим транзакций. Опции transaction_mode и init_command для SQLite появились в Django 5.1:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
"OPTIONS": {
"transaction_mode": "IMMEDIATE",
"timeout": 5,
"init_command": (
"PRAGMA journal_mode=WAL;"
"PRAGMA synchronous=NORMAL;"
),
},
},
}
journal_mode=WALпозволяет читать базу во время записи. Рядом с файлом базы появятся служебныеdb.sqlite3-walиdb.sqlite3-shm— при резервном копировании учитывайте их или используйте команду.backupконсолиsqlite3.transaction_mode: "IMMEDIATE"заставляет транзакцию сразу захватывать блокировку на запись. Тогда конкурирующая транзакция ждёт освобождения базы доtimeoutсекунд и только потом возвращаетdatabase is locked. Транзакции при этом должны быть короткими, поэтомуATOMIC_REQUESTSс этим режимом не рекомендуется.timeout— сколько секунд ждать освобождения блокировки. Увеличение таймаута откладывает ошибку, но не убирает причину — слишком много одновременных записей.
Проверить, что настройки применились, можно запросом PRAGMA через курсор (о нём ниже):
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("PRAGMA journal_mode")
print(cursor.fetchone()) # → ('wal',)
dbshell: консоль базы данных
python manage.py dbshell запускает консольный клиент СУБД и подключается к базе с параметрами из DATABASES — не нужно вручную вводить имя базы, пользователя и пароль:
| СУБД | Какой клиент запускается |
|---|---|
| PostgreSQL | psql |
| MySQL, MariaDB | mysql |
| SQLite | sqlite3 |
| Oracle | sqlplus |
Клиент должен быть в PATH: указать путь к нему вручную нельзя. Без него команда завершится ошибкой:
CommandError: You appear not to have the 'sqlite3' program installed or on your path.
Модуль sqlite3 в Python и консольная программа sqlite3 — разные вещи. Программу ставят отдельно:
# Windows
winget install SQLite.SQLite
# Ubuntu/Debian
sudo apt install sqlite3
# macOS — sqlite3 уже есть в системе
После установки откройте новый терминал, чтобы обновился PATH. Полезные команды внутри sqlite3:
sqlite> .tables -- список таблиц
sqlite> .schema library_book -- CREATE TABLE для таблицы
sqlite> .headers on
sqlite> .mode column -- вывод с заголовками и выравниванием
sqlite> SELECT id, title FROM library_book LIMIT 5;
sqlite> .quit
Параметры после -- передаются клиенту без изменений. Так можно выполнить один запрос без интерактивной консоли:
# SQLite: SQL-запрос передаётся вторым аргументом sqlite3
python manage.py dbshell -- "SELECT count(*) FROM library_book;"
# PostgreSQL: флаг -c у psql
python manage.py dbshell -- -c "select current_user"
# Консоль другой базы из DATABASES
python manage.py dbshell --database analytics
Если ставить программу sqlite3 не хочется, в Python 3.12+ есть встроенная консоль SQLite. Запрос передаётся вторым аргументом:
python -m sqlite3 db.sqlite3 "SELECT id, title, price FROM library_book"
(1, 'Изучаем Python', 2500)
(2, 'Чистый код', 1320)
(3, 'Django для профессионалов', 1800)
Точечных команд вроде .tables в ней нет: список таблиц выводит запрос SELECT name FROM sqlite_master WHERE type='table'. Для просмотра базы мышью подойдёт DB Browser for SQLite или вкладка Database в PyCharm.
Сырой SQL в Django
ORM покрывает большинство задач: фильтры, агрегаты, аннотации, подзапросы, F- и Q-выражения собраны в шпаргалке по Django ORM. Сырой SQL нужен для отчётов со сложными оконными функциями, специфичного синтаксиса СУБД или массовых операций, которые ORM выражает неэффективно. Примеры ниже используют модель:
# library/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
price = models.DecimalField(max_digits=8, decimal_places=2)
Таблица по умолчанию называется <приложение>_<модель> в нижнем регистре — здесь library_book. Другое имя задают в Meta.db_table (см. «Модели в Django»).
Как посмотреть SQL, который генерирует ORM
Прежде чем писать SQL вручную, посмотрите, что строит ORM. Атрибут query у QuerySet показывает запрос:
qs = Book.objects.filter(price__gt=1500).only("title")
print(qs.query)
# → SELECT "library_book"."id", "library_book"."title" FROM "library_book" WHERE "library_book"."price" > 1500
Это текст для чтения, выполнять его как есть нельзя: параметры подставлены без кавычек и экранирования. Например, для filter(author="Лутц") в выводе будет = Лутц. Точный запрос с параметрами возвращает qs.query.sql_with_params().
При DEBUG = True Django записывает все выполненные запросы и их время в connection.queries:
from django.db import connection, reset_queries
reset_queries()
list(Book.objects.filter(author="Лутц"))
print(len(connection.queries), connection.queries[-1]["sql"])
План выполнения показывает qs.explain() — на SQLite это вывод EXPLAIN QUERY PLAN, на PostgreSQL можно передать analyze=True. Для постоянного контроля числа запросов на страницах удобнее django-debug-toolbar; как убирать лишние запросы, разобрано в статье «N+1 в Django ORM».
Manager.raw(): SQL-запрос с моделями на выходе
raw() выполняет SELECT и возвращает объекты модели — с ними работают так же, как с результатами filter():
books = Book.objects.raw(
"SELECT * FROM library_book WHERE price > %s ORDER BY price",
[1500],
)
for book in books:
print(book.title, book.price)
Django для профессионалов 1800.00
Изучаем Python 2500.00
Правила raw():
- В выборке обязательно должен быть первичный ключ, иначе —
FieldDoesNotExist: Raw query must include the primary key. - Поля можно опустить: Django догрузит их отдельным запросом при обращении, и на каждую такую загрузку уйдёт ещё один запрос к базе.
- Колонки сопоставляются с полями модели по имени. Если имена не совпадают, используйте
ASв SQL или аргументtranslations:Book.objects.raw("SELECT id, title AS name FROM library_book", translations={"name": "title"}). raw()возвращаетRawQuerySet: у него нетfilter(),order_by()и других методов QuerySet. Индексы и срезы работают, но выполняются в Python — ограничивайте выборку черезLIMITв самом SQL.
connection.cursor(): SQL без моделей
Для UPDATE, DELETE, INSERT, агрегатов по нескольким таблицам и любых запросов, которые не ложатся на модель, берут курсор соединения:
from django.db import connection
with connection.cursor() as cursor:
cursor.execute(
"SELECT author, price FROM library_book WHERE price < %s", [2000]
)
print(cursor.fetchall()) # → [('Мартин', 1200), ('Винсент', 1800)]
cursor.execute(
"UPDATE library_book SET price = price * 1.1 WHERE author = %s",
["Мартин"],
)
print(cursor.rowcount) # → 1
fetchone() возвращает одну строку кортежем, fetchall() — список кортежей. Чтобы получить словари с именами колонок, используйте вспомогательную функцию:
def dictfetchall(cursor):
columns = [col[0] for col in cursor.description]
return [dict(zip(columns, row)) for row in cursor.fetchall()]
with connection.cursor() as cursor:
cursor.execute("SELECT id, title FROM library_book ORDER BY id")
print(dictfetchall(cursor))
# → [{'id': 1, 'title': 'Изучаем Python'}, {'id': 2, 'title': 'Чистый код'}, ...]
Для другой базы из DATABASES курсор берут через connections: connections["analytics"].cursor(). Запросы через курсор идут мимо моделей: сигналы pre_save и post_save, валидация и auto_now не срабатывают.
Защита от SQL-инъекций
SQL-инъекция — подстановка в запрос данных пользователя, которые меняют смысл SQL. Сравните два запроса с одним и тем же вводом:
user_input = "' OR '1'='1"
# Опасно: значение вставлено в строку SQL
books = Book.objects.raw(
f"SELECT * FROM library_book WHERE author = '{user_input}'"
)
print(len(list(books))) # → 3 — вернулись все книги
# Безопасно: значение передано параметром
books = Book.objects.raw(
"SELECT * FROM library_book WHERE author = %s", [user_input]
)
print(len(list(books))) # → 0
В первом случае условие превратилось в author = '' OR '1'='1' — оно истинно для любой строки. Во втором драйвер передал ввод как значение, и база искала автора с именем ' OR '1'='1.
Правила безопасного сырого SQL:
- Передавайте значения вторым аргументом
raw()илиexecute(). Никаких f-строк,format(),%и конкатенации. - Не ставьте кавычки вокруг
%s: запись'%s'снова открывает дорогу инъекции. - Используйте плейсхолдер
%sна всех СУБД, включая SQLite: Django сам преобразует его в синтаксис драйвера. Плейсхолдер?из модуляsqlite3в Django не работает: запрос упадёт сTypeError: not all arguments converted during string formatting. - Если в запросе с параметрами нужен символ процента, удваивайте его:
LIKE '%%Python%%'. - Параметром передаётся только значение. Имя таблицы, колонки или направление сортировки так не передать — сверяйте их со списком разрешённых вариантов:
ALLOWED_ORDER = {"title", "price"}
order = request.GET.get("order", "title")
if order not in ALLOWED_ORDER:
order = "title"
books = Book.objects.raw(f"SELECT * FROM library_book ORDER BY {order}")
ORM-методы (filter(), exclude(), update()) экранируют значения сами, поэтому чем меньше сырого SQL, тем меньше мест для ошибки. Фрагмент SQL внутри обычного QuerySet можно вставить через выражение RawSQL — к нему применимы те же правила о параметрах.
Несколько баз данных и роутеры
Django может работать с несколькими базами одновременно: отдельная база для аналитики, реплика только для чтения, унаследованная база другой системы. Каждая база описывается своим псевдонимом:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
},
"analytics": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "analytics.sqlite3",
},
}
Базу можно выбрать вручную:
Book.objects.using("analytics").filter(price__gt=1000)
book.save(using="analytics")
book.delete(using="analytics")
migrate работает с одной базой за раз — для каждой дополнительной запускайте его отдельно:
python manage.py migrate
python manage.py migrate --database=analytics
Роутер базы данных
Чтобы не писать using() в каждом запросе, правила выбора базы задают роутером — классом с методами db_for_read, db_for_write, allow_relation и allow_migrate. Метод возвращает псевдоним базы, True/False или None, если у роутера нет мнения. Пример: модели приложения stats живут в базе analytics, всё остальное — в default:
# config/routers.py
class AnalyticsRouter:
route_app_labels = {"stats"}
def db_for_read(self, model, **hints):
if model._meta.app_label in self.route_app_labels:
return "analytics"
return None
def db_for_write(self, model, **hints):
if model._meta.app_label in self.route_app_labels:
return "analytics"
return None
def allow_relation(self, obj1, obj2, **hints):
if (
obj1._meta.app_label in self.route_app_labels
or obj2._meta.app_label in self.route_app_labels
):
return obj1._meta.app_label == obj2._meta.app_label
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label in self.route_app_labels:
return db == "analytics"
return db == "default"
# config/settings.py
DATABASE_ROUTERS = ["config.routers.AnalyticsRouter"]
Теперь PageView.objects.create(...) из приложения stats пишет в analytics.sqlite3, а после двух команд migrate таблица stats_pageview есть только в analytics, таблицы остальных приложений — только в default.
Ограничения:
- Внешние ключи и связи «многие ко многим» между разными базами Django не поддерживает: связанные модели должны жить в одной базе.
- Встроенные приложения связаны между собой: модели
authдолжны быть в одной базе сcontenttypes, аadmin— в одной базе сauth. - Обращение к псевдониму, которого нет в
DATABASES, вызываетConnectionDoesNotExist: The connection 'users' doesn't exist.
Параметры подключения в переменных окружения
Пароль от базы в settings.py попадёт в git и во все копии репозитория. Читайте параметры из переменных окружения — тогда один и тот же код работает с SQLite на ноутбуке и с PostgreSQL на сервере:
# config/settings.py
import os
DATABASES = {
"default": {
"ENGINE": os.environ.get("DB_ENGINE", "django.db.backends.sqlite3"),
"NAME": os.environ.get("DB_NAME", BASE_DIR / "db.sqlite3"),
"USER": os.environ.get("DB_USER", ""),
"PASSWORD": os.environ.get("DB_PASSWORD", ""),
"HOST": os.environ.get("DB_HOST", ""),
"PORT": os.environ.get("DB_PORT", ""),
}
}
Без переменных проект работает на SQLite. На сервере их задают в окружении процесса, в unit-файле systemd, в docker compose или в файле .env:
# macOS/Linux
export DB_ENGINE=django.db.backends.postgresql
export DB_NAME=mysite DB_USER=mysite DB_PASSWORD=секрет DB_HOST=localhost
# Windows PowerShell
$env:DB_ENGINE = "django.db.backends.postgresql"
$env:DB_NAME = "mysite"; $env:DB_USER = "mysite"; $env:DB_PASSWORD = "секрет"; $env:DB_HOST = "localhost"
Файл .env Python сам не читает: подключите пакет python-dotenv или django-environ и добавьте .env в .gitignore. Если хостинг выдаёт строку подключения одной переменной DATABASE_URL, её разбирает пакет dj-database-url — пример есть в статье про подключение PostgreSQL. Как разделить настройки для разработки и продакшна, рассказано в статье о настройках Django.
Частые ошибки
| Ошибка | Причина и решение |
|---|---|
no such table: library_book | Миграции не применены к этой базе: python manage.py migrate (для другой базы — с --database) |
database is locked | Конкурирующие записи в SQLite: короткие транзакции, transaction_mode: "IMMEDIATE" и WAL или переход на PostgreSQL |
Error loading psycopg2 or psycopg module | Драйвер PostgreSQL не установлен в активное окружение: pip install "psycopg[binary]" |
Error loading MySQLdb module. Did you install mysqlclient? | Нет драйвера MySQL: pip install mysqlclient |
... isn't an available database backend | Опечатка в ENGINE |
You appear not to have the 'sqlite3' program installed | Для dbshell нужен консольный клиент СУБД в PATH |
Частые вопросы
Нужно ли добавлять db.sqlite3 в git?
Нет. Файл базы содержит данные, пароли пользователей в виде хешей и сессии, а при работе в команде постоянно вызывает конфликты. Добавьте db.sqlite3 в .gitignore. Структуру базы воспроизводят миграции, а начальные данные — фикстуры (dumpdata и loaddata) или скрипт.
Как очистить базу, не удаляя таблицы?
Команда python manage.py flush удаляет все данные и оставляет схему. Чтобы пересоздать базу целиком, удалите файл SQLite (на PostgreSQL и MySQL — пересоздайте базу) и выполните migrate. Обе операции необратимы.
Как подключить Django к существующей базе с готовыми таблицами?
Пропишите базу в DATABASES и выполните python manage.py inspectdb — Django сгенерирует модели по структуре таблиц. В сгенерированных моделях стоит managed = False: миграции не будут создавать и менять эти таблицы. Проверьте типы полей и первичные ключи вручную — генерация не всегда угадывает их точно.
Можно ли разрабатывать на SQLite, а в продакшне использовать PostgreSQL?
Технически да: код моделей и запросов ORM не меняется. Но поведение баз различается — регистр кириллицы в icontains, точность десятичных чисел, блокировки, типы полей. Ошибки всплывут уже на сервере, поэтому для проекта, который пойдёт в продакшн, локально запускайте ту же СУБД, например в Docker.
Как перенести данные из SQLite в PostgreSQL или MySQL?
Выгрузите данные командой dumpdata в JSON, переключите DATABASES на новую базу, выполните migrate и загрузите данные через loaddata. Какие таблицы исключить из выгрузки и как избежать проблем с кодировкой на Windows, показано в статье о PostgreSQL.
Чем raw() отличается от connection.cursor()?
raw() выполняет только SELECT и превращает строки в объекты модели — у них есть методы, связи и save(). Курсор выполняет любой SQL и возвращает кортежи, модели не участвуют. Если результат — записи одной модели, берите raw(); для отчётов, агрегатов и изменяющих запросов — курсор.
Итог
Подключение к базе в Django задаёт словарь DATABASES: ENGINE выбирает СУБД, остальные ключи описывают подключение, псевдоним default обязателен. SQLite по умолчанию хватает для обучения, тестов и небольших сайтов на одном сервере. Для параллельной записи, нескольких серверов и поиска по русскому тексту без учёта регистра переходите на PostgreSQL или MySQL. Консоль базы открывает dbshell, сырой SQL выполняют через raw() и connection.cursor() — всегда с параметрами отдельным аргументом, а пароли держат в переменных окружения.
- #Django
- #Базы данных
- #SQLite
- #DATABASES
- #SQL