Базы данных
Django официально поддерживает следующие базы данных:
Также имеется ряд баз данных, предоставляемых сторонними разработчиками.
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 13 и выше. Требуется psycopg 3.1.8+ или psycopg2 2.8.4+, хотя рекомендуется последняя версия psycopg 3.1.8+.
Примечание
Поддержка psycopg2 вероятно будет устаревать и удалена в какой-то момент в будущем.
Настройки подключения PostgreSQL
См. HOST для подробностей.
Чтобы подключиться, используя имя службы из файла службы соединения https://www.postgresql.org/docs/current/libpq-pgservice.html и пароль из файла паролей https://www.postgresql.org/docs/current/libpq-pgpass.html, вы должны указать их в части 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 https://www.postgresql.org/docs/current/transaction-iso.html. Если вам нужен более высокий уровень изоляции, например, 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 по умолчанию:
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.
Курсоры на стороне сервера PostgreSQL
При использовании 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 на недолговечность.
Предупреждение
Это опасно: это сделает вашу базу данных более уязвимой к потере или повреждению данных в случае сбоя сервера или отключения питания. Используйте только на машинe разработки, где вы легко можете восстановить всё содержимое всех баз данных в кластере.
Примечания по MariaDB
Django поддерживает MariaDB 10.5 и выше.
Для использования 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 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 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.
Точки сохранения
Как 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 |
|---|---|---|
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, так как их интеграция была бы достаточно сложной.
Обработка десятичных значений
В SQLite нет реального внутреннего типа decimal. Десятичные значения преобразуются во внутренний тип REAL (8-байтовое число с плавающей запятой IEEE), как описано в документации по типам данных SQLite, поэтому они не поддерживают корректное округление десятичной арифметики с плавающей запятой.
“Ошибка базы данных заблокирована”
SQLite предназначен для лёгкого использования и не может поддерживать высокую степень конкуретности. Ошибки OperationalError: database is locked указывают на то, что ваше приложение испытывает больше конкуретности, чем sqlite может обработать в стандартной конфигурации. Эта ошибка означает, что один поток или процесс имеет эксклюзивную блокировку соединения с базой данных, а другой поток превысил время ожидания получения блокировки.
В Python-обёртке SQLite есть значение по умолчанию для таймаута, определяющее, как долго второй поток может ожидать блокировки, прежде чем он истечёт и выдаст ошибку 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()
Существуют особые соображения, описанные в Изоляции в SQLite при изменении таблицы во время итерации по ней с помощью QuerySet.iterator(). Если строка добавляется, изменяется или удаляется в цикле, то эта строка может или не появиться, или может появиться дважды в последующих результатах, полученных из итератора. Ваш код должен обрабатывать эту ситуацию.
Включение расширения JSON1 в SQLite
Для использования JSONField в SQLite необходимо включить расширение JSON1 в библиотеке Python sqlite3. Если расширение не включено в вашей установке, будет поднята системная ошибка (fields.E180).
Чтобы включить расширение JSON1, вы можете следовать инструкциям на странице вики.
Примечание
Расширение JSON1 включено по умолчанию в SQLite 3.38+.
Настройка параметров 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 поддерживает версии сервера баз данных Oracle 19c и выше. Требуется версия 1.3.2 или выше 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
Строку полного 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)))"
)
Параметр threaded
Если вы планируете запустить 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 в одном из этих полей на самом деле означает пустую строку, и данные молча преобразуются в соответствии с этим предположением.
Ограничения бэкенда Oracle
Бэкенд 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/5.1/ref/databases/