Spec-Zone.ru › Django 5.2

Базы данных

Django официально поддерживает следующие базы данных:

  • PostgreSQL
  • MariaDB
  • MySQL
  • Oracle
  • SQLite

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

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

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

Общие замечания

Персистентные подключения

Персистентные подключения избегают накладных расходов на повторное установление соединения с базой данных в каждом запросе HTTP. Они управляются параметром CONN_MAX_AGE, который определяет максимальную продолжительность жизни соединения. Его можно задать независимо для каждой базы данных.

Значение по умолчанию — 0, сохраняя историческое поведение закрытия соединения с базой данных в конце каждого запроса. Чтобы включить персистентные подключения, задайте CONN_MAX_AGE положительное целое число в секундах. Для неограниченных персистентных подключений установите его в None.

Управление подключениями

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

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

В начале каждого запроса Django закрывает соединение, если оно достигло максимального возраста. Если ваша база данных закрывает бездействующие соединения после некоторого времени, вы должны установить CONN_MAX_AGE на более низкое значение, чтобы Django не пытался использовать соединение, которое было закрыто сервером базы данных. (Эта проблема может затрагивать только сайты с очень низким трафиком.)

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

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

Ограничения

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

Иногда база данных не будет использоваться большинством ваших представлений, например, потому, что это база данных внешней системы или благодаря кэшированию. В таких случаях вы должны установить CONN_MAX_AGE на низкое значение или даже на 0, потому что не имеет смысла поддерживать соединение, которое вряд ли будет повторно использоваться. Это поможет сохранить небольшое количество одновременных соединений с этой базой данных.

Сервер разработки создает новый поток для каждого обрабатываемого запроса, что сводит на нет эффект персистентных соединений. Не включайте их во время разработки.

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

Если соединение создается в процессе с длительной обработкой, вне цикла запроса-ответа Django, соединение останется открытым до явного закрытия или истечения срока действия таймаута. Вы можете использовать django.db.close_old_connections() для закрытия всех устаревших или непригодных для использования соединений.

Кодировка

Django предполагает, что все базы данных используют кодировку UTF-8. Использование других кодировок может привести к неожиданному поведению, например, к ошибкам «значение слишком длинное» в вашей базе данных для данных, которые являются допустимыми в Django. См. Примечания по конкретным базам данных ниже, чтобы узнать, как правильно настроить свою базу данных.

Заметки по PostgreSQL

Django поддерживает PostgreSQL 14 и выше. Требуется psycopg 3.1.8+ или psycopg2 2.8.4+, хотя рекомендуется последняя версия psycopg 3.1.8+.

Примечание

Поддержка psycopg2, вероятно, будет устаревшей и удаленной в будущем.

Настройки подключения к PostgreSQL

Подробную информацию см. в HOST.

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

settings.py
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "OPTIONS": {
            "service": "my_service",
            "passfile": ".my_pgpass",
        },
    }
}
.pg_service.conf
[my_service]
host=localhost
user=USER
dbname=NAME
port=5432
.my_pgpass
localhost:5432:NAME:USER:PASSWORD

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

Предупреждение

Использование имени службы для целей тестирования не поддерживается. Это может быть реализовано позже.

Оптимизация конфигурации PostgreSQL

Django требует следующих параметров для подключений к базе данных:

  • client_encoding: 'UTF8',
  • default_transaction_isolation: 'read committed' по умолчанию или значение, заданное в параметрах подключения (см. ниже),
  • timezone:
    • когда USE_TZ равно True, 'UTC' по умолчанию или значение TIME_ZONE, установленное для подключения,
    • когда USE_TZ равно False, значение глобальной настройки TIME_ZONE.

Если эти параметры уже имеют правильные значения, Django не будет их устанавливать для каждого нового подключения, что немного улучшает производительность. Вы можете настроить их напрямую в postgresql.conf или более удобно для каждого пользователя базы данных с помощью ALTER ROLE.

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

Уровень изоляции

Как и сам PostgreSQL, Django по умолчанию использует уровень изоляции READ COMMITTED уровень изоляции. Если вам нужен более высокий уровень изоляции, например, REPEATABLE READ или SERIALIZABLE, установите его в части OPTIONS вашей конфигурации базы данных в DATABASES:

from django.db.backends.postgresql.psycopg_any import IsolationLevel

DATABASES = {
    # ...
    "OPTIONS": {
        "isolation_level": IsolationLevel.SERIALIZABLE,
    },
}

Примечание

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

Роль

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

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        # ...
        "OPTIONS": {
            "assume_role": "my_application_role",
        },
    },
}

Пул подключений

Новое в Django 5.1.

Чтобы использовать пул подключений с psycopg, вы можете либо установить "pool" в части OPTIONS вашей конфигурации базы данных в DATABASES как словарь, который будет передан в ConnectionPool, или установить True, чтобы использовать параметры ConnectionPool по умолчанию:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        # ...
        "OPTIONS": {
            "pool": True,
        },
    },
}

Для этого параметра требуется наличие psycopg[pool] или psycopg-pool и игнорируется при использовании psycopg2.

Связывание параметров на стороне сервера

С psycopg 3.1.8+, Django по умолчанию использует курсоры со связыванием на стороне клиента. Если вы хотите использовать связывание на стороне сервера, установите его в части OPTIONS вашей конфигурации базы данных в DATABASES:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        # ...
        "OPTIONS": {
            "server_side_binding": True,
        },
    },
}

Этот параметр игнорируется при использовании psycopg2.

Индексы для полей типа varchar и text

При указании db_index=True для полей модели Django обычно генерирует одно выражение CREATE INDEX. Однако, если тип базы данных для поля равен varchar или text (например, используется в CharField, FileField и TextField), Django создаст дополнительный индекс, использующий соответствующий операторный класс PostgreSQL для столбца. Дополнительный индекс необходим для корректного выполнения запросов, использующих оператор LIKE в своём SQL, как это делается с типами запросов contains и startswith.

Операция миграции для добавления расширений

Если вам нужно добавить расширение PostgreSQL (например, hstore, postgis и т. д.) с помощью миграции, используйте операцию CreateExtension.

Побочные курсоры на стороне сервера

При использовании QuerySet.iterator(), Django открывает побочный курсор на стороне сервера. По умолчанию PostgreSQL предполагает, что будет извлечено только первые 10% результатов запросов курсора. Планировщик запросов тратит меньше времени на планирование запроса и начинает возвращать результаты быстрее, но это может ухудшить производительность, если извлекается более 10% результатов. Предположения PostgreSQL о количестве строк, извлекаемых для запроса курсора, управляются параметром cursor_tuple_fraction.

Пулы транзакций и побочные курсоры на стороне сервера

Использование пула соединений в режиме пула транзакций (например, PgBouncer) требует отключения побочных курсоров на стороне сервера для данного соединения.

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

Одним из решений является отключение побочных курсоров на стороне сервера для соединения в DATABASES, установив DISABLE_SERVER_SIDE_CURSORS в True.

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

Другим вариантом является обертка каждого QuerySet с побочными курсорами на стороне сервера в блоке atomic(), так как это отключает autocommit на время транзакции. Таким образом, побочный курсор на стороне сервера будет существовать только на время транзакции.

Ручное задание значений автоинкрементируемых первичных ключей

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

>>> from django.contrib.auth.models import User
>>> User.objects.create(username="alice", pk=1)
<User: alice>
>>> # The sequence hasn't been updated; its next value is 1.
>>> User.objects.create(username="bob")
IntegrityError: duplicate key value violates unique constraint
"auth_user_pkey" DETAIL:  Key (id)=(1) already exists.

Если вам нужно указать такие значения, после этого сбросьте последовательность, чтобы избежать повторного использования значения, уже присутствующего в таблице. Команда управления sqlsequencereset генерирует SQL-запросы для этого.

Шаблоны тестовых баз данных

Вы можете использовать настройку TEST['TEMPLATE'], чтобы указать шаблон (например, 'template0') для создания тестовой базы данных.

Ускорение выполнения тестов с настройками недолговечности

Вы можете ускорить выполнение тестов, настроив PostgreSQL для недолговечности.

Предупреждение

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

Примечания по MariaDB

Django поддерживает MariaDB 10.5 и выше.

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

Примечания по MySQL

Поддержка версий

Django поддерживает MySQL 8.0.11 и выше.

Функция Django inspectdb использует базу данных information_schema, которая содержит подробные данные обо всех схемах баз данных.

Django ожидает, что база данных поддерживает Unicode (кодировка UTF-8) и делегирует ей задачу обеспечения транзакций и целостности ссылок. Важно помнить, что последние две не на самом деле поддерживаются MySQL при использовании движка хранения MyISAM, см. следующий раздел.

Движки хранения

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

По умолчанию в MySQL используется движок хранения InnoDB. Этот движок полностью транзакционный и поддерживает внешние ключи. Это рекомендуемый выбор. Однако счётчик автоинкремента InnoDB теряется при перезапуске MySQL, поскольку он не запоминает значение AUTO_INCREMENT, а вместо этого пересоздаёт его как «max(id)+1». Это может привести к непреднамеренному повторному использованию значений AutoField.

Основные недостатки движка MyISAM заключаются в том, что он не поддерживает транзакции или проверку ограничений внешних ключей.

Драйверы MySQL DB API

MySQL имеет несколько драйверов, которые реализуют Python Database API, описанный в PEP 249:

  • mysqlclient — это родной драйвер. Он рекомендуется.
  • MySQL Connector/Python — это чисто Python-драйвер от Oracle, который не требует библиотеки MySQL-клиента или каких-либо Python-модулей, кроме стандартной библиотеки.

В дополнение к драйверу DB API, Django нуждается в адаптере для доступа к драйверам баз данных из своего ORM. Django предоставляет адаптер для mysqlclient, а MySQL Connector/Python включает свой.

mysqlclient

Django требует mysqlclient 1.4.3 или более поздней версии.

MySQL Connector/Python

MySQL Connector/Python доступен на странице загрузки. Адаптер Django доступен в версиях 1.1.X и более поздних. Он может не поддерживать самые последние релизы Django.

Определения часовых поясов

Если вы планируете использовать поддержку часовых поясов Django, используйте mysql_tzinfo_to_sql для загрузки таблиц часовых поясов в базу данных MySQL. Это нужно сделать только один раз для вашего сервера MySQL, а не для каждой базы данных.

Создание вашей базы данных

Вы можете создать свою базу данных с помощью командной строки и следующего SQL:

CREATE DATABASE <dbname> CHARACTER SET utf8mb4;

Это гарантирует, что все таблицы и столбцы будут использовать UTF-8 по умолчанию.

Настройки сортировки

Настройка сортировки для столбца управляет порядком сортировки данных, а также тем, какие строки считаются равными. Вы можете указать параметр db_collation, чтобы установить имя сортировки столбца для CharField и TextField.

Сортировку также можно задать на уровне всей базы данных и на уровне каждой таблицы. Это подробно описано в документации MySQL. В таких случаях вам необходимо настроить сортировку, непосредственно изменяя параметры базы данных или таблицы. Django не предоставляет API для их изменения.

По умолчанию, с базой данных UTF-8, MySQL будет использовать сортировку utf8mb4_0900_ai_ci. Это приводит к тому, что все сравнения строк на равенство выполняются в регистронезависимом режиме. То есть, "Fred" и "freD" считаются равными на уровне базы данных. Если у вас есть ограничение уникальности на поле, попытка вставить в этот столбец как "aa", так и "AA" будет недопустима, так как они сравниваются как равные (и, следовательно, не уникальные) с сортировкой по умолчанию. Если вам нужны регистрозависимые сравнения в конкретном столбце или таблице, измените столбец или таблицу на использование сортировки utf8mb4_0900_as_cs.

Обратите внимание, что, согласно наборам символов Unicode MySQL, сравнения для сортировки utf8mb4_general_ci быстрее, но немного менее точны, чем сравнения для utf8mb4_unicode_ci. Если это приемлемо для вашего приложения, используйте utf8mb4_general_ci, потому что она быстрее. Если это неприемлемо (например, если вам требуется немецкий порядок словаря), используйте utf8mb4_unicode_ci, потому что она более точна.

Предупреждение

Наборы форм модели проверяют уникальные поля в регистрозависимом режиме. Таким образом, при использовании регистронезависимой сортировки набор форм с уникальными значениями поля, отличающимися только регистром, пройдёт проверку, но при вызове save() будет вызвано исключение IntegrityError.

Подключение к базе данных

Обратитесь к документации по настройкам.

Настройки подключения используются в таком порядке:

  1. OPTIONS.
  2. NAME, USER, PASSWORD, HOST, PORT
  3. Файлы опций MySQL.

Другими словами, если вы установите имя базы данных в OPTIONS, это будет иметь приоритет над NAME, что переопределит любые параметры в файле опций MySQL .

Вот пример конфигурации, использующей файл опций MySQL:

# settings.py
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "OPTIONS": {
            "read_default_file": "/path/to/my.cnf",
        },
    }
}
# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8mb4

Несколько других параметров подключения MySQLdb могут быть полезны, такие как ssl, init_command и sql_mode.

Установка режима SQL

Значение по умолчанию для параметра sql_mode содержит STRICT_TRANS_TABLES. Этот параметр преобразует предупреждения в ошибки при усечении данных при вставке, поэтому Django настоятельно рекомендует активировать режим строгости для MySQL, чтобы предотвратить потерю данных (либо STRICT_TRANS_TABLES, либо STRICT_ALL_TABLES).

Если вам нужно настроить режим SQL, вы можете установить переменную sql_mode, как и другие параметры MySQL: либо в файле конфигурации, либо с помощью записи 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'" в части OPTIONS вашей конфигурации базы данных в DATABASES.

Уровень изоляции

При одновременной работе транзакции баз данных из разных сеансов (например, разных потоков, обрабатывающих разные запросы) могут взаимодействовать друг с другом. Эти взаимодействия зависят от уровня изоляции транзакций каждой сессии . Вы можете установить уровень изоляции соединения с помощью записи 'isolation_level' в части OPTIONS вашей конфигурации базы данных в DATABASES. Действительными значениями для этой записи являются четыре стандартных уровня изоляции:

  • 'read uncommitted'
  • 'read committed'
  • 'repeatable read'
  • 'serializable'

или None, чтобы использовать уровень изоляции, заданный на сервере. Однако Django лучше всего работает с режимом "read committed", а не с режимом MySQL по умолчанию "repeatable read". Потеря данных возможна с "repeatable read". В частности, вы можете столкнуться с ситуациями, когда get_or_create() вызовет IntegrityError, но объект не появится в последующем вызове get().

Создание таблиц

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

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

  • После создания таблиц выполните оператор ALTER TABLE, чтобы преобразовать таблицу в новый движок хранения (например, InnoDB):

    ALTER TABLE <tablename> ENGINE=INNODB;
    

    Это может быть утомительно, если у вас много таблиц.

  • Другой вариант — использовать параметр init_command для MySQLdb перед созданием таблиц:

    "OPTIONS": {
        "init_command": "SET default_storage_engine=INNODB",
    }
    

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

Имена таблиц

В даже последних версиях MySQL существуют известные проблемы, которые могут привести к изменению регистра имени таблицы при выполнении определённых SQL-запросов в определённых условиях. Рекомендуется использовать имена таблиц в нижнем регистре, если это возможно, чтобы избежать проблем, которые могут возникнуть из-за этого поведения. Django использует имена таблиц в нижнем регистре при автоматической генерации имён таблиц из моделей, поэтому это необходимо учитывать, только если вы переопределяете имя таблицы с помощью параметра db_table.

Точки сохранения

Как ORM Django, так и MySQL (при использовании движка хранения InnoDB движок хранения) поддерживают точки сохранения базы данных точки сохранения.

Если вы используете движок хранения MyISAM, имейте в виду, что при попытке использовать методы API транзакций, связанные с точками сохранения, вы получите ошибки, сгенерированные базой данных. Причина в том, что определение движка хранения базы данных/таблицы MySQL является дорогостоящей операцией, поэтому было решено, что не стоит динамически преобразовывать эти методы в no-op, основываясь на результатах такого определения.

Примечания к определённым полям

Поля символьных данных

Для полей, хранящихся с типами столбцов VARCHAR, может быть ограничено значение max_length до 255 символов, если вы используете unique=True для поля. Это влияет на CharField, SlugField. Более подробную информацию см. в документации MySQL.

TextField ограничения

MySQL может индексировать только первые N символов столбца BLOB или TEXT. Поскольку у TextField нет определённой длины, вы не можете пометить его как unique=True. MySQL выдаст сообщение об ошибке: «Столбец BLOB/TEXT ‘<db_column>’ используется в спецификации ключа без длины ключа».

Поддержка дробных секунд для полей Time и DateTime

MySQL может хранить дробные секунды, при условии, что определение столбца включает дробное указание (например, DATETIME(6)).

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

ALTER TABLE `your_table` MODIFY `your_datetime_column` DATETIME(6)

или используя операцию RunSQL в миграциях данных.

TIMESTAMP столбцы

Если вы используете старую базу данных, содержащую TIMESTAMP столбцы, вы должны установить USE_TZ = False, чтобы избежать повреждения данных. inspectdb сопоставляет эти столбцы с DateTimeField, и если вы включите поддержку часовых поясов, как MySQL, так и Django будут пытаться преобразовать значения из UTC в местное время.

Блокировка строк с помощью QuerySet.select_for_update()

MySQL и MariaDB не поддерживают некоторые параметры оператора SELECT ... FOR UPDATE. Если select_for_update() используется с параметром, который не поддерживается, то возникает NotSupportedError.

Параметр

MariaDB

MySQL

SKIP LOCKED

X (≥10.6)

X

NOWAIT

X

X

OF

X

NO KEY

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

Автоматическое приведение типов может привести к неожиданным результатам

При выполнении запроса к строковому типу, но с целочисленным значением, MySQL приведет типы всех значений в таблице к целочисленному типу перед выполнением сравнения. Если ваша таблица содержит значения 'abc', 'def', и вы выполняете запрос для WHERE mycolumn=0, обе строки будут соответствовать. Аналогично, WHERE mycolumn=1 будет соответствовать значению 'abc1'. Следовательно, поля строкового типа, включённые в Django, всегда преобразуют значение в строку перед использованием в запросе.

Если вы реализуете пользовательские поля модели, которые наследуют от Field напрямую, переопределяете get_prep_value() или используете RawSQL, extra() или raw(), вам следует убедиться, что вы выполняете соответствующее приведение типов.

Заметки по SQLite

Django поддерживает SQLite 3.31.0 и более поздние версии.

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

Сопоставление подстрок и регистрозависимость

Для всех версий SQLite существует несколько неожиданное поведение при попытке сопоставить некоторые типы строк. Это поведение возникает при использовании фильтров iexact или contains в наборах запросов. Поведение делится на два случая:

1. Для сопоставления подстрок все сопоставления выполняются без учета регистра. То есть, фильтр, такой как filter(name__contains="aa"), будет соответствовать имени "Aabb".

2. Для строк, содержащих символы за пределами ASCII-диапазона, все точные сопоставления строк выполняются с учетом регистра, даже если в запрос передаются параметры для поиска без учета регистра. Таким образом, фильтр iexact будет вести себя точно так же, как фильтр exact в этих случаях.

Возможные обходные пути описаны на sqlite.org, но они не используются по умолчанию в SQLite-бекенде Django, так как их реализация в надежном формате довольно сложна. Таким образом, Django предоставляет поведение SQLite по умолчанию, и об этом следует помнить при использовании фильтров без учета регистра или по подстрокам.

Обработка десятичных чисел

SQLite не имеет внутреннего типа данных для десятичных чисел. Значения Decimal преобразуются во внутренний тип данных REAL (8-байтовое число с плавающей запятой IEEE), как описано в документации по типам данных SQLite https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes, поэтому они не поддерживают корректное округление десятичных чисел с плавающей запятой.

Ошибки «База данных заблокирована»

SQLite предназначен для использования в качестве легкой базы данных и, следовательно, не может поддерживать высокую степень конкурентности. Ошибки OperationalError: database is locked указывают на то, что ваше приложение испытывает большую конкурентность, чем sqlite может обработать в стандартной конфигурации. Эта ошибка означает, что один поток или процесс имеет эксклюзивную блокировку подключения к базе данных, а другой поток превысил время ожидания получения блокировки.

Обертка SQLite в Python имеет значение таймаута по умолчанию, которое определяет, как долго второй поток может ожидать блокировки, прежде чем истечет время ожидания и будет выброшена ошибка OperationalError: database is locked.

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

  • Переключиться на другой бэкенд базы данных. В какой-то момент SQLite становится слишком «легким» для реальных приложений, и подобные ошибки конкурентности указывают на то, что вы достигли этой точки.
  • Переписать свой код для уменьшения конкурентности и обеспечения того, чтобы транзакции базы данных были кратковременными.
  • Увеличьте значение таймаута по умолчанию, установив параметр базы данных timeout:

    "OPTIONS": {
        # ...
        "timeout": 20,
        # ...
    }
    

    Это позволит SQLite подождать немного дольше, прежде чем сгенерировать ошибки «база данных заблокирована»; это не решит проблемы с ними.

Поведение транзакций

Новое в Django 5.1.

SQLite поддерживает три режима транзакций: DEFERRED, IMMEDIATE и EXCLUSIVE.

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

"OPTIONS": {
    # ...
    "transaction_mode": "IMMEDIATE",
    # ...
}

Чтобы убедиться, что ваши транзакции ожидают timeout прежде чем выбросить ошибку «База данных заблокирована», измените режим транзакций на IMMEDIATE.

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

Дополнительную информацию см. в Документации по транзакциям в SQLite.

QuerySet.select_for_update() не поддерживается

SQLite не поддерживает синтаксис SELECT ... FOR UPDATE. Его использование не повлияет на работу.

Изоляция при использовании QuerySet.iterator()

Существуют особые соображения, описанные в Изоляции в SQLite, при модификации таблицы во время итерации по ней с помощью QuerySet.iterator(). Если строка добавлена, изменена или удалена внутри цикла, то эта строка может или не может появиться, или может появиться дважды в последующих результатах, полученных от итератора. Ваш код должен обрабатывать это.

Включение расширения JSON1 в SQLite

Для использования JSONField в SQLite необходимо включить расширение JSON1 в библиотеке Python sqlite3. Если расширение не включено в вашей установке, будет выброшено системное сообщение об ошибке (fields.E180).

Чтобы включить расширение JSON1, вы можете следовать инструкциям на странице wiki.

Примечание

Расширение JSON1 включено по умолчанию в SQLite 3.38+.

Настройка параметров pragma

Новое в Django 5.1.

Параметры pragma могут быть настроены при подключении с помощью init_command в части конфигурации базы данных OPTIONS в файле DATABASES. Пример ниже показывает, как включить дополнительную надежность синхронных записей и изменить cache_size:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        # ...
        "OPTIONS": {
            "init_command": "PRAGMA synchronous=3; PRAGMA cache_size=2000;",
        },
    }
}

Заметки по Oracle

Django поддерживает версии Oracle Database Server 19c и выше. Требуется версия 2.3.0 или выше Python-драйвера oracledb.

Устарело начиная с версии 5.0: Поддержка cx_Oracle устарела.

Для работы команды python manage.py migrate, пользователю вашей базы данных Oracle необходимы привилегии для выполнения следующих команд:

  • CREATE TABLE
  • CREATE SEQUENCE
  • CREATE PROCEDURE
  • CREATE TRIGGER

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

  • CREATE USER
  • ALTER USER
  • DROP USER
  • CREATE TABLESPACE
  • DROP TABLESPACE
  • CREATE SESSION WITH ADMIN OPTION
  • CREATE TABLE WITH ADMIN OPTION
  • CREATE SEQUENCE WITH ADMIN OPTION
  • CREATE PROCEDURE WITH ADMIN OPTION
  • CREATE TRIGGER WITH ADMIN OPTION

Хотя роль RESOURCE имеет необходимые привилегии CREATE TABLE, CREATE SEQUENCE, CREATE PROCEDURE и CREATE TRIGGER, и пользователь, которому предоставлены привилегии RESOURCE WITH ADMIN OPTION, может предоставить привилегии RESOURCE, такой пользователь не может предоставить отдельные привилегии (например, CREATE TABLE), и поэтому RESOURCE WITH ADMIN OPTION обычно недостаточно для запуска тестов.

Некоторые наборы тестов также создают представления или материализованные представления; для их запуска пользователю также необходимы привилегии CREATE VIEW WITH ADMIN OPTION и CREATE MATERIALIZED VIEW WITH ADMIN OPTION. В частности, это необходимо для собственного набора тестов Django.

Все эти привилегии включены в роль DBA, которая подходит для использования на базе данных частного разработчика.

Бэкенд базы данных Oracle использует пакеты SYS.DBMS_LOB и SYS.DBMS_RANDOM, поэтому пользователю потребуется право выполнения для них. Обычно он доступен всем пользователям по умолчанию, но если это не так, вам потребуется предоставить права следующим образом:

GRANT EXECUTE ON SYS.DBMS_LOB TO user;
GRANT EXECUTE ON SYS.DBMS_RANDOM TO user;

Подключение к базе данных

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

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.oracle",
        "NAME": "xe",
        "USER": "a_user",
        "PASSWORD": "a_password",
        "HOST": "",
        "PORT": "",
    }
}

В этом случае вы должны оставить как HOST, так и PORT пустыми. Однако, если вы не используете файл tnsnames.ora или аналогичный метод именования и хотите подключиться с помощью SID («xe» в этом примере), заполните как HOST, так и PORT следующим образом:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.oracle",
        "NAME": "xe",
        "USER": "a_user",
        "PASSWORD": "a_password",
        "HOST": "dbprod01ned.mycompany.com",
        "PORT": "1540",
    }
}

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

Полный DSN и Easy Connect

Строка Full DSN или Easy Connect может использоваться в NAME, если HOST и PORT пусты. Этот формат требуется при использовании RAC или подключаемых баз данных без tnsnames.ora, например.

Пример строки Easy Connect:

"NAME": "localhost:1521/orclpdb1"

Пример полной строки DSN:

"NAME": (
    "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))"
    "(CONNECT_DATA=(SERVICE_NAME=orclpdb1)))"
)

Пул подключений

Новое в Django 5.2.

Для использования пула подключений с oracledb, установите "pool" в True в части OPTIONS вашей конфигурации базы данных. Это использует значения по умолчанию функции драйвера create_pool():

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.oracle",
        # ...
        "OPTIONS": {
            "pool": True,
        },
    },
}

Для передачи пользовательских параметров функции драйвера create_pool(), вы можете вместо этого установить "pool" в виде словаря:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.oracle",
        # ...
        "OPTIONS": {
            "pool": {
                "min": 1,
                "max": 10,
                # ...
            }
        },
    },
}

Параметр потоков

Если вы планируете запускать Django в многопоточной среде (например, Apache с использованием модуля MPM по умолчанию на любой современной операционной системе), то вы обязательно должны установить параметр threaded вашей конфигурации базы данных Oracle на True:

"OPTIONS": {
    "threaded": True,
}

Отказ от этого может привести к сбоям и другим странным ошибкам.

INSERT … RETURNING INTO

По умолчанию бэкенд Oracle использует предложение RETURNING INTO для эффективного извлечения значения AutoField при вставке новых строк. Это поведение может привести к DatabaseError в некоторых необычных настройках, таких как вставка в удалённую таблицу или в представление с триггером INSTEAD OF. Предложение RETURNING INTO можно отключить, установив параметр use_returning_into конфигурации базы данных на False:

"OPTIONS": {
    "use_returning_into": False,
}

В этом случае бэкенд Oracle будет использовать отдельный запрос SELECT для получения значений AutoField.

Проблемы с именами

Oracle накладывает ограничение на длину имени в 30 символов. Для этого бэкенд усекает идентификаторы базы данных до соответствия, заменяя последние четыре символа усеченного имени повторяющимся значением MD5. Кроме того, бэкенд преобразует идентификаторы базы данных в верхний регистр.

Чтобы предотвратить эти преобразования (это обычно требуется только при работе со старыми базами данных или доступе к таблицам, которые принадлежат другим пользователям), используйте цитируемое имя в качестве значения для db_table:

class LegacyModel(models.Model):
    class Meta:
        db_table = '"name_left_in_lowercase"'


class ForeignModel(models.Model):
    class Meta:
        db_table = '"OTHER_USER"."NAME_ONLY_SEEMS_OVER_30"'

Цитируемые имена также могут использоваться с другими поддерживаемыми бэкендами баз данных Django; за исключением Oracle, однако, кавычки не оказывают никакого эффекта.

При запуске migrate, может возникнуть ошибка ORA-06552, если некоторые ключевые слова Oracle используются в качестве имени поля модели или значения опции db_column. Django цитирует все идентификаторы, используемые в запросах, чтобы предотвратить большинство таких проблем, но эта ошибка всё ещё может возникнуть, когда тип данных Oracle используется в качестве имени столбца. В частности, будьте внимательны, чтобы не использовать имена date, timestamp, number или float в качестве имени поля.

NULL и пустые строки

Django обычно предпочитает использовать пустую строку ('') вместо NULL, но Oracle обрабатывает оба одинаково. Чтобы обойти это, бэкенд Oracle игнорирует явную опцию null для полей, имеющих пустую строку в качестве возможного значения, и генерирует DDL так, как будто null=True. При извлечении из базы данных предполагается, что значение NULL в одном из этих полей на самом деле означает пустую строку, и данные молча преобразуются, чтобы отразить это предположение.

TextField ограничения

Бэкенд Oracle хранит TextFields как столбцы NCLOB. Oracle накладывает некоторые ограничения на использование таких столбцов LOB в целом:

  • Столбцы LOB не могут использоваться в качестве первичных ключей.
  • Столбцы LOB не могут использоваться в индексах.
  • Столбцы LOB не могут использоваться в списке SELECT DISTINCT. Это означает, что попытка использовать метод QuerySet.distinct на модели, которая включает столбцы TextField, приведёт к ошибке ORA-00932 при запуске против Oracle. В качестве обходного пути, используйте метод QuerySet.defer в сочетании с distinct(), чтобы предотвратить включение столбцов TextField в список SELECT DISTINCT.

Наследование встроенных бэкэндов баз данных

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

Предположим, например, что вам нужно изменить одну функцию базы данных. Сначала нужно создать новую директорию с модулем base в нём. Например:

mysite/
    ...
    mydbengine/
        __init__.py
        base.py

Модуль base.py должен содержать класс с именем DatabaseWrapper, который наследуется от существующего движка из модуля django.db.backends. Вот пример наследования движка PostgreSQL для изменения класса функции allows_group_by_selected_pks_on_model:

mysite/mydbengine/base.py
from django.db.backends.postgresql import base, features


class DatabaseFeatures(features.DatabaseFeatures):
    def allows_group_by_selected_pks_on_model(self, model):
        return True


class DatabaseWrapper(base.DatabaseWrapper):
    features_class = DatabaseFeatures

Наконец, необходимо указать DATABASE-ENGINE в вашем файле settings.py:

DATABASES = {
    "default": {
        "ENGINE": "mydbengine",
        # ...
    },
}

Список текущих движков баз данных можно найти в django/db/backends.

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

Помимо официально поддерживаемых баз данных, существуют бэкэнды сторонних разработчиков, которые позволяют использовать другие базы данных с Django:

  • CockroachDB
  • Firebird
  • Google Cloud Spanner
  • Microsoft SQL Server
  • Snowflake
  • TiDB
  • YugabyteDB

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

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.2/ref/databases/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API