Spec-Zone.ru › Django 3.0

Базы данных

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

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

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

Кодировка

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

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

Django поддерживает PostgreSQL 9.5 и выше. Требуется psycopg2 2.5.4 или выше, хотя рекомендуется последняя версия.

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

См. HOST для подробностей.

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

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

  • client_encoding: 'UTF8',
  • default_transaction_isolation: 'read committed' по умолчанию, или значение, заданное в параметрах соединения (см. ниже),
  • timezone: 'UTC' при USE_TZ равно True, значение 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.

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

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

Пулы транзакций и курсоры на стороне сервера

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

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

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

END_OF_DOCUMENT_MARKER

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

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

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

Django использует тип данных PostgreSQL SERIAL для хранения автоинкрементируемых первичных ключей. Столбец 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 на недолговечные значения.

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

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

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

Новое в Django 3.0.

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

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

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

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

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

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

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

Движки хранилища

MySQL имеет несколько движков хранилища. Вы можете изменить стандартный движок хранилища в конфигурации сервера.

Стандартным движком хранилища MySQL является InnoDB. Этот движок полностью транзакционный и поддерживает ссылки на внешние ключи. Это рекомендуемый выбор. Однако счётчик автоинкремента InnoDB теряется при перезапуске MySQL, потому что он не запоминает значение AUTO_INCREMENT, а вместо этого пересоздаёт его как «max(id)+1». Это может привести к непреднамеренному повторному использованию значений AutoField.

Основными недостатками MyISAM являются то, что он не поддерживает транзакции или не проверяет внешние ключи.

Драйверы API базы данных MySQL

MySQL имеет несколько драйверов, которые реализуют API базы данных Python, описанный в PEP 249:

  • mysqlclient — это драйвер нативно. Это рекомендуемый выбор.
  • MySQL Connector/Python — это драйвер на чистом Python от Oracle, который не требует библиотеки MySQL-клиента или каких-либо модулей Python за пределами стандартной библиотеки.

Эти драйверы потокобезопасны и обеспечивают пул подключений.

В дополнение к драйверу API базы данных Django нуждается в адаптере для доступа к драйверам баз данных из своего ORM. Django предоставляет адаптер для mysqlclient, а MySQL Connector/Python включает свой собственный.

mysqlclient

Django требует mysqlclient 1.3.13 или более поздней версии.

MySQL Connector/Python

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

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

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

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

Вы можете создать свою базу данных с помощью командной строки и этого SQL:

CREATE DATABASE <dbname> CHARACTER SET utf8;

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

Настройки сортировки MySQL

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

По умолчанию в базе данных 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.

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

См. документацию по настройкам.

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

  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 и при свежих установках MySQL 5.6, значение параметра 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.

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

MySQL может индексировать только первые N символов BLOB или TEXT столбца. Поскольку TextField не имеет определённой длины, вы не можете пометить его как unique=True. MySQL сообщит об ошибке: “BLOB/TEXT column ‘<db_column>’ used in key specification without a key length”.

Поддержка дробных секунд для полей Time и DateTime

MySQL 5.6.4 и более поздние версии могут хранить дробные секунды при условии, что определение столбца включает дробное обозначение (например, 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 (≥8.0.1)
NOWAIT X (≥10.3) X (≥8.0.1)
OF

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

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

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

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

1. При сопоставлении по подстроке все сопоставления выполняются без учета регистра. Например, фильтр filter(name__contains="aa") будет соответствовать имени "Aabb".

2. Для строк, содержащих символы за пределами диапазона ASCII, все точные сопоставления строк выполняются с учетом регистра, даже если в запрос передаются опции без учета регистра. Таким образом, фильтр iexact будет вести себя точно так же, как фильтр exact в этих случаях.

Некоторые возможные решения этой проблемы описаны на сайте sqlite.org, но они не используются в стандартном SQLite-бекенде Django, так как их внедрение было бы довольно сложным и надежным.

Следовательно, Django использует поведение SQLite по умолчанию, и вам следует учитывать это при выполнении фильтрации без учета регистра или по подстрокам.

Обработка десятичных значений

SQLite не имеет собственного внутреннего типа данных для десятичных значений. Десятичные значения внутри преобразуются в тип данных 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» в запросах без поддержки

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

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

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

Заметки об Oracle

Django поддерживает Сервер базы данных Oracle версии 12.2 и выше. Требуется версия 6.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 и Легкое Подключение

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

Пример строки лёгкого подключения:

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

Пример строки полного DSN:

'NAME': (
    '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))'
    '(CONNECT_DATA=(SERVICE_NAME=orclpdb1)))'
),

Многопоточный параметр

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

'OPTIONS': {
    'threaded': True,
},

Отказ от этого может привести к сбоям и другому странному поведению.

INSERT … ВОЗВРАЩЕНИЕ В

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

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

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

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

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

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

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

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

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

При запуске migrate, может возникнуть ошибка ORA-06552, если в качестве имени поля модели или значения параметра db_column используются определённые ключевые слова Oracle. 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:

  • CockroachDB
  • Firebird
  • Microsoft SQL Server

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

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

Spec-Zone.ru

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