Spec-Zone.ru › Django 4.1

Базы данных

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

  • PostgreSQL
  • MariaDB
  • MySQL
  • Oracle
  • SQLite

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

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 может повысить надежность повторного использования соединений и предотвратить ошибки, когда соединение было закрыто сервером базы данных, который теперь готов принимать и обслуживать новые соединения, например, после перезапуска сервера базы данных. Проверка работоспособности выполняется только один раз на запрос и только если к базе данных обращаются во время обработки запроса.

Изменено в Django 4.1:

Добавлен параметр CONN_HEALTH_CHECKS.

Ограничения

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

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

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

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

Кодировка

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

Примечания к PostgreSQL

Django поддерживает PostgreSQL 11 и выше. Требуется psycopg2 2.8.4 или выше, хотя рекомендуется использовать последнюю версию.

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

См. HOST для получения подробной информации.

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

settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'OPTIONS': {
            'service': 'my_service',
            'passfile': '.my_pgpass',
        },
    }
}
.pg_service.conf
[my_service]
host=localhost
user=USER
dbname=NAME
port=5432
.my_pgpass
localhost:5432:NAME:USER:PASSWORD
Изменено в Django 4.0:

Была добавлена поддержка подключения по имени службы и указания файла паролей.

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

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

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

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

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

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

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

Уровень изоляции базы данных

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

import psycopg2.extensions

DATABASES = {
    # ...
    'OPTIONS': {
        'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE,
    },
}

Примечание

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

Индексы для 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 использует тип данных SERIAL PostgreSQL для хранения автоинкрементируемых первичных ключей. Столбец SERIAL заполняется значениями из последовательности, которая отслеживает следующее доступное значение. Ручное присвоение значения полю с автоинкрементом не обновляет последовательность поля, что может привести к конфликту в будущем. Например:

>>> 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.3 и выше.

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

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

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

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

Функция 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.0 или новее.

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.

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

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

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

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

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

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

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file': '/path/to/my.cnf',
        },
    }
}


# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8

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

Установка sql_mode

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

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

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

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

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

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

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

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

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

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

    ALTER TABLE <tablename> ENGINE=INNODB;
    

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

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

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

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

Имена таблиц

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

Сохраняемые точки

Как 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.

END_OF_DOCUMENT_MARKER
Вариант 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.9.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. Вызов его не повлияет на результат.

Стиль параметра «pyformat» в запросах raw не поддерживается

Для большинства бэкендов запросы raw (Manager.raw() или cursor.execute()) могут использовать стиль параметра «pyformat», где плейсхолдеры в запросе задаются как '%(name)s', а параметры передаются в виде словаря, а не списка. SQLite не поддерживает это.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Полный DSN и Easy Connect

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

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

'NAME': 'localhost:1521/orclpdb1',

Пример строки Full 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 … RETURNING INTO

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

'OPTIONS': {
    'use_returning_into': False,
},

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

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

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

Чтобы предотвратить эти преобразования (это обычно требуется только при работе с устаревшими базами данных или доступе к таблицам, которые принадлежат другим пользователям), используйте имя в кавычках в качестве значения для 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 backend игнорирует явную опцию null для полей, которые могут иметь пустую строку в качестве значения, и генерирует DDL так, как если бы null=True. При извлечении из базы данных предполагается, что значение NULL в одном из этих полей фактически означает пустую строку, и данные безмолвно преобразуются в соответствии с этим предположением.

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

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

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

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

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

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

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

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

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

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

class DatabaseWrapper(base.DatabaseWrapper):
    features_class = DatabaseFeatures

Наконец, вы должны указать DATABASE-ENGINE в своём файле settings.py:

DATABASES = {
    'default': {
        'ENGINE': 'mydbengine',
        ...
    },
}

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

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

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

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

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

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

Spec-Zone.ru

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