Базы данных

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

Существует также ряд database backends provided by third parties.

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

Заметки о PostgreSQL

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

Примечание

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

Changed in Django 4.2:

Добавлена поддержка psycopg 3.1.8+.

Настройки подключения к 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

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

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

Оптимизация конфигурации 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:

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

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

Примечание

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

Changed in Django 4.2:

Было добавлено IsolationLevel.

Роль

New in Django 4.2.

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

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

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

New in Django 4.2.

В версии psycopg 3.1.8+ Django по умолчанию использует client-side binding cursors. Если вы хотите использовать server-side binding, установите его в 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 operator class для столбца. Дополнительный индекс необходим для корректного выполнения поиска, использующего оператор LIKE в SQL, как это делается с типами поиска contains и startswith.

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

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

Курсоры на стороне сервера

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

Объединение транзакций и курсоры на стороне сервера

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

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

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

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

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

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

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

>>> 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'], чтобы указать template (например, 'template0'), на основе которого будет создана тестовая база данных.

Ускорение выполнения тестов с помощью недолговечных настроек

Вы можете ускорить время выполнения теста с помощью configuring PostgreSQL to be non-durable.

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

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

Заметки о MariaDB

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

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

Заметки по MySQL

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

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

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

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

Двигатели для хранения

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

По умолчанию в 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 включает its own.

mysqlclient

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

MySQL Connector/Python

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

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

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

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

Вы можете create your database использовать средства командной строки и данный SQL:

CREATE DATABASE <dbname> CHARACTER SET utf8;

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

Настройки колляции

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

Колляцию также можно установить на уровне всей базы данных и для каждой таблицы. Об этом говорится в документации MySQL documented thoroughly. В таких случаях вы должны установить collation, непосредственно манипулируя настройками базы данных или таблицами. Django не предоставляет API для их изменения.

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

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

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

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

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

Обратитесь к settings documentation.

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

  1. OPTIONS.
  2. NAME, USER, PASSWORD, HOST, PORT
  3. Файлы параметров MySQL.

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

Вот пример конфигурации, в которой используется файл опций 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 connection options, например ssl, init_command и sql_mode.

Установка sql_mode

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

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

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

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

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

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

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

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

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

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

    ALTER TABLE <tablename> ENGINE=INNODB;
    

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

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

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

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

Названия таблиц

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

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

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

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

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

Поля символов

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

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 в операции data migration.

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.27.0 и более поздние версии.

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

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

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

1. For substring matching, all matches are done case-insensitively. That is a filter such as filter(name__contains="aa") will match a name of "Aabb".

2. For strings containing characters outside the ASCII range, all exact string matches are performed case-sensitively, even when the case-insensitive options are passed into the query. So the iexact filter will behave exactly the same as the exact filter in these cases.

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

Работа с десятичными дробями

SQLite не имеет реального десятичного внутреннего типа. Десятичные значения внутренне преобразуются в тип данных REAL (8-байтовое число IEEE с плавающей точкой), как объясняется в SQLite datatypes documentation, поэтому они не поддерживают правильно округленную десятичную арифметику с плавающей точкой.

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

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

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

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

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

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

  • Увеличьте значение тайм-аута по умолчанию, установив параметр базы данных timeout:

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

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

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

SQLite не поддерживает синтаксис SELECT ... FOR UPDATE. Его вызов не даст никакого эффекта.

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

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

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

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

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

Примечание

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

Заметки Oracle

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

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

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

  • СОЗДАТЬ ТАБЛИЦУ
  • СОЗДАТЬ ПОСЛЕДОВАТЕЛЬНОСТЬ
  • СОЗДАТЬ ПРОЦЕДУРУ
  • СОЗДАТЬ ТРИГГЕР

Чтобы запустить тестовый пакет проекта, пользователю обычно нужны эти дополнительные привилегии:

  • СОЗДАТЬ ПОЛЬЗОВАТЕЛЯ
  • ПЕРЕМЕННЫЙ ПОЛЬЗОВАТЕЛЬ
  • УВОЛИТЬ ПОЛЬЗОВАТЕЛЯ
  • СОЗДАТЬ ТАБЛИЧНОЕ ПРОСТРАНСТВО
  • СБРОСИТЬ ТАБЛИЧНОЕ ПРОСТРАНСТВО
  • СОЗДАТЬ СЕАНС С ВОЗМОЖНОСТЬЮ АДМИНИСТРИРОВАНИЯ
  • СОЗДАНИЕ ТАБЛИЦЫ С ВОЗМОЖНОСТЬЮ АДМИНИСТРИРОВАНИЯ
  • СОЗДАНИЕ ПОСЛЕДОВАТЕЛЬНОСТИ С ПОМОЩЬЮ ОПЦИИ АДМИНИСТРАТОРА
  • СОЗДАНИЕ ПРОЦЕДУРЫ С ВОЗМОЖНОСТЬЮ АДМИНИСТРИРОВАНИЯ
  • СОЗДАНИЕ ТРИГГЕРА С ВОЗМОЖНОСТЬЮ АДМИНИСТРИРОВАНИЯ

Хотя роль 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)))"
)

Вариант с резьбой

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

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

Невыполнение этого требования может привести к сбоям и другим странным действиям.

ВСТАВИТЬ … ВОЗВРАЩЕНИЕ В

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

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

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

Вопросы наименования

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


class DatabaseWrapper(base.DatabaseWrapper):
    features_class = DatabaseFeatures

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

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

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

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

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

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

Вернуться на верх