Базы данных
Django официально поддерживает следующие базы данных:
Также существует ряд бэкэндов баз данных, предоставляемых сторонними разработчиками.
Django пытается поддерживать как можно больше функций на всех бэкэндах баз данных. Однако все бэкэнды баз данных не одинаковы, и нам пришлось принять решения о том, какие функции поддерживать и какие предположения можно сделать безопасно.
В этом файле описываются некоторые функции, которые могут быть актуальны для использования Django. Он не предназначен для замены документации, специфичной для сервера, или справочных руководств.
Общие замечания
Персистентные подключения
Персистентные подключения избегают накладных расходов на повторное установление соединения с базой данных в каждом запросе. Они контролируются параметром 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_HEALTH_CHECKS.
Ограничения
Поскольку каждый поток поддерживает собственное соединение, ваша база данных должна поддерживать как минимум такое же количество одновременных подключений, как у вас потоков обработки.
Иногда к базе данных не обращаются большинство ваших представлений, например, потому что это база данных внешней системы или благодаря кэшированию. В таких случаях вы должны установить CONN_MAX_AGE на низкое значение или даже на 0, потому что не имеет смысла поддерживать соединение, которое, скорее всего, не будет повторно использовано. Это поможет сохранить небольшое количество одновременных подключений к этой базе данных.
Сервер разработки создает новый поток для каждого запроса, который он обрабатывает, тем самым отрицая эффект персистентных подключений. Не включайте их во время разработки.
Когда Django устанавливает соединение с базой данных, он настраивает соответствующие параметры в зависимости от используемого бэкэнда. Если вы включите персистентные подключения, эта настройка больше не будет повторяться в каждом запросе. Если вы изменяете параметры, такие как уровень изоляции подключения или часовой пояс, вам следует либо восстановить значения по умолчанию Django в конце каждого запроса, либо принудительно задать соответствующее значение в начале каждого запроса, либо отключить персистентные подключения.
Кодировка
Django предполагает, что все базы данных используют кодировку UTF-8. Использование других кодировок может привести к неожиданному поведению, например, к ошибкам «значение слишком длинное» со стороны базы данных для данных, которые допустимы в Django. См. Примечания к конкретной базе данных ниже, чтобы узнать, как правильно настроить вашу базу данных.
Примечания к PostgreSQL
Django поддерживает PostgreSQL 12 и выше. Требуется psycopg 3.1.8+ или psycopg2 2.8.4+, хотя рекомендуется последняя версия psycopg 3.1.8+.
Примечание
Поддержка psycopg2 вероятно будет устаревать и удалена в какой-то момент в будущем.
Добавлена поддержка psycopg 3.1.8+.
Параметры подключения 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
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,
},
}
Примечание
При более высоких уровнях изоляции ваше приложение должно быть готово обрабатывать исключения, возникающие при сбоях сериализации. Этот параметр предназначен для продвинутых задач.
Добавлен IsolationLevel.
Роль
Если вам нужно использовать другую роль для подключений к базе данных, отличную от роли, используемой для установления подключения, установите ее в части OPTIONS конфигурации базы данных в DATABASES:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
# ...
"OPTIONS": {
"assume_role": "my_application_role",
},
},
}
Привязка параметров сервера базы данных
С 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-команды для этого.
В более старых версиях вместо идентификационных столбцов использовался тип данных PostgreSQL SERIAL.
Шаблоны тестовой базы данных
Вы можете использовать параметр TEST['TEMPLATE'] для указания шаблона (например, 'template0') для создания тестовой базы данных.
Ускорение выполнения тестов с недолговечными настройками
Вы можете ускорить время выполнения тестов, настроив PostgreSQL для недолговечности.
Предупреждение
Это опасно: это сделает вашу базу данных более уязвимой к потере или повреждению данных в случае сбоя сервера или отключения электропитания. Используйте это только на машине разработки, где вы можете легко восстановить содержимое всех баз данных в кластере.
Примечания по MariaDB
Django поддерживает MariaDB 10.4 и выше.
Для использования MariaDB используйте бэкенд MySQL, который используется для обоих. Более подробную информацию см. в примечаниях по MySQL.
Примечания по MySQL
Поддержка версий
Django поддерживает MySQL 8 и выше.
Функция 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 1.4.3 или более поздней версии.
MySQL Connector/Python
MySQL Connector/Python доступен на странице загрузки. Адаптер Django доступен в версиях 1.1.X и выше. Он может не поддерживать самые последние версии Django.
Определения часовых поясов MySQL
Если вы планируете использовать поддержку часовых поясов Django, используйте mysql_tzinfo_to_sql для загрузки таблиц часовых поясов в базу данных MySQL. Это нужно сделать один раз для вашего сервера MySQL, а не для каждой базы данных.
Создание вашей базы данных
Вы можете создать свою базу данных с помощью командной строки и этого SQL:
CREATE DATABASE <dbname> CHARACTER SET utf8;
Это гарантирует, что все таблицы и столбцы по умолчанию будут использовать UTF-8.
Настройки сортировки
Настройка сортировки столбца управляет порядком сортировки данных, а также тем, какие строки считаются равными. Вы можете указать параметр db_collation для установки имени сортировки столбца для CharField и TextField.
Сортировка также может быть установлена на уровне всей базы данных и каждой таблицы. Это подробно документировано в документации MySQL. В таких случаях вы должны установить сортировку, напрямую манипулируя настройками базы данных или таблицами. Django не предоставляет API для их изменения.
По умолчанию, с базой данных UTF-8, MySQL будет использовать сортировку utf8_general_ci. Это приводит к тому, что все сравнения строк на равенство выполняются в режиме регистронезависимого сравнения. То есть, "Fred" и "freD" считаются равными на уровне базы данных. Если у вас есть уникальное ограничение на поле, попытка вставки "aa" и "AA" в один и тот же столбец будет невозможна, так как они считаются равными (и, следовательно, не уникальными) с использованием сортировки по умолчанию. Если вам требуется регистрозависимое сравнение для определенного столбца или таблицы, измените столбец или таблицу на использование сортировки utf8_bin.
Обратите внимание, что в соответствии с наборами символов MySQL Unicode, сравнения для сортировки utf8_general_ci быстрее, но немного менее точны, чем сравнения для utf8_unicode_ci. Если это приемлемо для вашего приложения, вы должны использовать utf8_general_ci, так как оно быстрее. Если это неприемлемо (например, если вам требуется немецкий порядок словаря), используйте utf8_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 = utf8
Некоторые другие опции подключения 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 лучше всего работает с и по умолчанию использует «read committed», а не «repeatable read», который является значением по умолчанию в MySQL. При использовании «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.
Точки сохранения
Как Django ORM, так и 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 (≥8.0.1) |
NOWAIT | X | X (≥8.0.1) |
OF | X (≥8.0.1) | |
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.21.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, поэтому они не поддерживают корректное округление десятичных чисел с плавающей точкой.
“Ошибка блокировки базы данных”
SQLite предназначен для использования в качестве лёгкой базы данных, и поэтому не может поддерживать высокий уровень конкурентности. Ошибки OperationalError: database is locked указывают на то, что ваше приложение испытывает больше конкурентности, чем sqlite может обработать по умолчанию. Эта ошибка означает, что один поток или процесс имеет эксклюзивную блокировку соединения с базой данных, а другой поток превысил время ожидания блокировки.
В Python-обёртке SQLite есть значение таймаута по умолчанию, которое определяет, как долго второй поток может ждать блокировки, прежде чем он завершит ожидание и поднимет ошибку OperationalError: database
is locked.
Если вы получаете эту ошибку, вы можете её решить:
- Переключиться на другой бэкенд базы данных. В определенный момент SQLite становится слишком «лёгким» для реальных приложений, и подобные ошибки конкурентности указывают на то, что вы достигли этого предела.
- Переписать свой код, чтобы уменьшить конкурентность и обеспечить, что транзакции базы данных будут непродолжительными.
-
Увеличьте значение таймаута по умолчанию, установив параметр базы данных
timeout:"OPTIONS": { # ... "timeout": 20, # ... }Это позволит SQLite подождать немного дольше, прежде чем генерировать ошибки «база данных заблокирована»; это не решит проблему.
QuerySet.select_for_update() не поддерживается
SQLite не поддерживает синтаксис SELECT ... FOR UPDATE. Вызов этого синтаксиса не приведет к каким-либо действиям.
Изоляция при использовании QuerySet.iterator()
При модификации таблицы во время итерации по ней с использованием QuerySet.iterator() необходимо учитывать особые моменты, описанные в Изоляция в SQLite. Если строка добавляется, изменяется или удаляется внутри цикла, эта строка может или не может появиться, или может появиться дважды в последующих результатах, полученных от итератора. Ваш код должен обрабатывать этот случай.
Включение расширения JSON1 в SQLite
Для использования JSONField в SQLite необходимо включить расширение JSON1 в библиотеке Python sqlite3. Если расширение не включено в вашей установке, будет поднята системная ошибка (fields.E180)
Чтобы включить расширение JSON1, вы можете следовать инструкциям на странице wiki.
Примечание
Расширение JSON1 включено по умолчанию в SQLite 3.38+.
Примечания к Oracle
Django поддерживает Oracle Database Server версии 19c и выше. Требуется версия Python-драйвера cx_Oracle 7.0 или выше.
Для работы команды 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 и легкое подключение
Строка полного DSN или легкого подключения может быть использована в NAME, если и HOST, и PORT пусты. Этот формат необходим при использовании RAC или подключаемых баз данных без tnsnames.ora, например.
Пример строки легкого подключения:
"NAME": "localhost:1521/orclpdb1"
Пример строки полного DSN:
"NAME": (
"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))"
"(CONNECT_DATA=(SERVICE_NAME=orclpdb1)))"
)
Многопоточный вариант
Если вы планируете запускать Django в многопоточной среде (например, Apache с модулем MPM по умолчанию на любой современной операционной системе), то вы обязаны установить параметр threaded вашей конфигурации Oracle базы данных на значение True:
"OPTIONS": {
"threaded": True,
}
Отсутствие этого параметра может привести к сбоям и другим странным ошибкам.
INSERT … ВЕРНУТЬ В
По умолчанию, бэкенд 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.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/4.2/ref/databases/