Базы данных
Django официально поддерживает следующие базы данных:
Также существует ряд серверных частей для баз данных, предоставляемых сторонними разработчиками.
Django стремится поддерживать как можно больше возможностей во всех серверных частях баз данных. Однако серверные части баз данных различаются, поэтому нам пришлось решить, какие возможности поддерживать и какие предположения можно безопасно делать.
В этом файле описаны некоторые возможности, которые могут иметь значение при использовании Django. Он не предназначен для замены документации или справочных руководств по конкретным серверам.
Общие сведения
Постоянные подключения
Постоянные подключения позволяют избежать затрат на повторное подключение к базе данных при каждом HTTP-запросе. Они управляются параметром CONN_MAX_AGE, который определяет максимальное время жизни подключения. Его можно задавать отдельно для каждой базы данных.
Значение по умолчанию — 0, что сохраняет прежнее поведение: подключение к базе данных закрывается в конце каждого запроса. Чтобы включить постоянные подключения, задайте для CONN_MAX_AGE положительное целое число секунд. Для неограниченного срока действия постоянных подключений задайте значение None.
При использовании ASGI постоянные подключения следует отключить. Вместо этого используйте встроенный пул подключений вашей серверной части базы данных, если он доступен, или при необходимости рассмотрите стороннее решение для организации пула подключений.
Управление подключениями
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.12+ или psycopg2 версии 2.9.9+, хотя рекомендуется последняя версия psycopg 3.1.12+.
Примечание
Поддержка psycopg2, вероятно, в будущем будет объявлена устаревшей и удалена.
Параметры подключения к PostgreSQL
Подробнее см. HOST.
Чтобы подключиться, указав имя службы из файла служб подключения и пароль из файла паролей, необходимо указать их в части OPTIONS конфигурации базы данных в DATABASES:
settings.pyDATABASES = {
"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_pgpasslocalhost:5432:NAME:USER:PASSWORD
Серверная часть PostgreSQL передает содержимое OPTIONS конструктору подключения в виде именованных аргументов, позволяя более гибко управлять поведением драйвера. Все доступные параметры подробно описаны в документации PostgreSQL.
Предупреждение
Использование имени службы для тестирования не поддерживается. Это может быть реализовано позднее.
Оптимизация конфигурации PostgreSQL
Для подключений к базе данных Django требуются следующие параметры:
-
client_encoding:'UTF8', -
default_transaction_isolation: по умолчанию'read committed'или значение, заданное в параметрах подключения (см. ниже),
Если эти параметры уже имеют нужные значения, 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",
},
},
}
Пул подключений
Чтобы использовать пул подключений с 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 для столбца. Дополнительный индекс необходим для правильного выполнения поисковых запросов, в SQL которых используется оператор LIKE, как это происходит при поиске с типами 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.6 и выше.
Чтобы использовать MariaDB, выберите серверную часть MySQL, общую для обеих баз данных. Подробнее см. примечания по MySQL.
Примечания по MySQL
Поддерживаемые версии
Django поддерживает MySQL 8.0.11 и более поздние версии.
Функция inspectdb в Django использует базу данных 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 версии 2.2.1 или новее.
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.
Подключение к базе данных
См. документацию по настройкам.
Параметры подключения используются в следующем порядке:
Иными словами, если имя базы данных задано в 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_mode
Значение параметра 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 лучше всего работает с уровнем «чтение зафиксированных данных» и использует его по умолчанию вместо уровня MySQL по умолчанию — «повторяемое чтение». При повторяемом чтении возможна потеря данных. В частности, возможны ситуации, когда 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 — затратная операция, и было решено, что динамически превращать эти методы в пустые операции на основании результатов такой проверки нецелесообразно.
Примечания к отдельным полям
Символьные поля
Для любых полей, хранящихся в столбцах типа 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 |
|---|---|---|
| X | X |
| X | X |
| X | |
|
При использовании 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 нет настоящего внутреннего десятичного типа. Десятичные значения внутри преобразуются в тип данных REAL (число с плавающей запятой IEEE размером 8 байт), как объясняется в документации по типам данных SQLite, поэтому корректно округлённая десятичная арифметика с плавающей запятой не поддерживается.
Ошибки «База данных заблокирована»
SQLite предназначена для работы в качестве лёгкой базы данных и поэтому не поддерживает высокий уровень параллелизма. Ошибки OperationalError: database is locked означают, что приложение испытывает большую параллельную нагрузку, чем sqlite может обработать в конфигурации по умолчанию. Эта ошибка означает, что один поток или процесс установил исключительную блокировку подключения к базе данных, а другой поток ожидал снятия блокировки и не дождался.
В оболочке SQLite для Python задано значение времени ожидания по умолчанию, определяющее, как долго второй поток может ждать снятия блокировки, прежде чем истечёт время ожидания и будет вызвана ошибка OperationalError: database is locked.
Если вы столкнулись с этой ошибкой, её можно устранить следующими способами:
- Перейти на другой бэкенд базы данных. В какой-то момент SQLite становится слишком «лёгкой» для реальных приложений, и подобные ошибки параллелизма означают, что вы достигли этого предела.
- Переписать код, чтобы уменьшить параллельную нагрузку и сделать транзакции базы данных короткими.
-
Увеличить значение времени ожидания по умолчанию, задав параметр базы данных
timeout:"OPTIONS": { # ... "timeout": 20, # ... }Это заставит SQLite немного дольше ждать, прежде чем выдавать ошибку «база данных заблокирована», но на самом деле не устранит её причину.
Поведение транзакций
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()
При изменении таблицы во время её перебора с помощью QuerySet.iterator() следует учитывать особенности, описанные в разделе «Изоляция в SQLite». Если строка добавляется, изменяется или удаляется внутри цикла, она может как появиться, так и не появиться в последующих результатах, полученных из итератора; также она может появиться дважды. Ваш код должен это учитывать.
Включение расширения JSON1 в SQLite
Чтобы использовать JSONField в SQLite, необходимо включить расширение JSON1 в библиотеке sqlite3 Python. Если расширение не включено в вашей установке, будет вызвана системная ошибка (fields.E180).
Чтобы включить расширение JSON1, следуйте инструкциям на странице вики.
Примечание
В SQLite 3.38 и новее расширение JSON1 включено по умолчанию.
Настройка параметров pragma
Параметры 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 поддерживает версии 19c и выше сервера Oracle Database. Требуется версия 2.3.0 или выше драйвера Python oracledb.
Чтобы команда 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
Если оба параметра HOST и PORT пусты, в NAME можно использовать строку полного DSN или Easy Connect. Например, этот формат необходим при использовании RAC или подключаемых баз данных без tnsnames.ora.
Пример строки Easy Connect:
"NAME": "localhost:1521/orclpdb1"
Пример строки полного DSN:
"NAME": (
"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))"
"(CONNECT_DATA=(SERVICE_NAME=orclpdb1)))"
)
Пул подключений
Чтобы использовать пул подключений с 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,
# ...
}
},
},
}
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, если в качестве имени поля модели или значения параметра db_column используются определённые ключевые слова Oracle. Django заключает все используемые в запросах идентификаторы в кавычки, чтобы избежать большинства таких проблем, но эта ошибка всё ещё может возникнуть, если в качестве имени столбца используется тип данных Oracle. В частности, не используйте имена date, timestamp, number или float для полей.
NULL и пустые строки
Django обычно предпочитает использовать пустую строку (''), а не NULL, но Oracle обрабатывает их одинаково. Чтобы обойти это ограничение, бэкенд Oracle игнорирует явно заданный параметр null для полей, допускающих пустую строку, и генерирует DDL так, как если бы было указано null=True. При получении данных из базы предполагается, что значение NULL в одном из таких полей на самом деле означает пустую строку; данные незаметно преобразуются в соответствии с этим предположением.
ограничения TextField
Бэкенд Oracle хранит каждый TextField в столбце 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.pyfrom 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 другие базы данных:
Версии Django и возможности ORM, поддерживаемые этими неофициальными бэкендами, существенно различаются. Вопросы о возможностях конкретных неофициальных бэкендов, а также запросы в службу поддержки следует направлять по каналам поддержки, предоставленным каждым сторонним проектом.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/ref/databases/