Django-Admin.ru

Базы данных в Django: настройка DATABASES и SQLite

Как Django работает с базой данных: поддерживаемые СУБД, настройка DATABASES, SQLite по умолчанию, dbshell, сырой SQL без инъекций и несколько баз.

Редакция Django-Admin.ru
· 19 мин чтения

Содержание · 10 разделов
  1. Какие базы данных поддерживает Django
  2. Настройка DATABASES в settings.py
  3. SQLite в Django по умолчанию
  4. Когда SQLite хватает
  5. Особенности SQLite, которые удивляют
  6. Настройка SQLite для продакшна
  7. dbshell: консоль базы данных
  8. Сырой SQL в Django
  9. Как посмотреть SQL, который генерирует ORM
  10. Manager.raw(): SQL-запрос с моделями на выходе
  11. connection.cursor(): SQL без моделей
  12. Защита от SQL-инъекций
  13. Несколько баз данных и роутеры
  14. Роутер базы данных
  15. Параметры подключения в переменных окружения
  16. Частые ошибки
  17. Частые вопросы
  18. Нужно ли добавлять db.sqlite3 в git?
  19. Как очистить базу, не удаляя таблицы?
  20. Как подключить Django к существующей базе с готовыми таблицами?
  21. Можно ли разрабатывать на SQLite, а в продакшне использовать PostgreSQL?
  22. Как перенести данные из SQLite в PostgreSQL или MySQL?
  23. Чем raw() отличается от connection.cursor()?
  24. Итог

База данных в 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.1Django 5.2 LTS
PostgreSQLdjango.db.backends.postgresqlpsycopg 3.1.12+ или psycopg2 2.9.9+15 и новее14 и новее
MariaDBdjango.db.backends.mysqlmysqlclient 2.2.1+10.11 и новее10.5 и новее
MySQLdjango.db.backends.mysqlmysqlclient 2.2.1+8.4 и новее8.0.11 и новее
SQLitedjango.db.backends.sqlite3модуль sqlite3 из стандартной библиотеки3.37.0 и новее3.31.0 и новее
Oracledjango.db.backends.oracleoracledb 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_AGE0Сколько секунд держать соединение открытым; 0 — закрывать после каждого запроса
CONN_HEALTH_CHECKSFalseПроверять переиспользуемое соединение перед запросом
ATOMIC_REQUESTSFalseОборачивать каждое представление (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 — не нужно вручную вводить имя базы, пользователя и пароль:

СУБДКакой клиент запускается
PostgreSQLpsql
MySQL, MariaDBmysql
SQLitesqlite3
Oraclesqlplus

Клиент должен быть в 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
↑ ↓ выборEnter открытьEsc закрыть