Spec-Zone.ru › Django 2.1

Базы данных

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.4 и выше. Требуется psycopg2 2.5.4 по 2.7.7, хотя рекомендуется 2.7.7.

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

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

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

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

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

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

Функциональность Django с inspectdb использует базу данных 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.3.7 или новее.

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.

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

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

По умолчанию, с базой данных 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 и на новых установках 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», а не режим «repeatable read», который является по умолчанию для MySQL. Возможность потери данных при использовании режима «repeatable read».

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

В более старых версиях бэкэнд MySQL по умолчанию использует уровень изоляции базы данных (который по умолчанию равен «repeatable read»), а не «read committed».

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

При генерации схемы 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 ‘<db_column>’ используется в спецификации ключа без длины ключа».

Поддержка дробных секунд для полей 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 не поддерживает NOWAIT, SKIP LOCKED, и OF опции оператора SELECT ... FOR UPDATE. Если select_for_update() используется с nowait=True, skip_locked=True, или of, то генерируется NotSupportedError.

Автоматическое приведение типов может привести к неожиданным результатам

При выполнении запроса к строковому типу, но с целочисленным значением, MySQL приведет типы всех значений в таблице к целочисленному типу перед выполнением сравнения. Если ваша таблица содержит значения 'abc', 'def', и вы выполняете запрос на WHERE mycolumn=0, обе строки будут соответствовать. Аналогично, WHERE mycolumn=1 будет соответствовать значению 'abc1'. Следовательно, поля строкового типа в Django всегда преобразуют значение в строку перед использованием его в запросе.

Если вы реализуете пользовательские поля модели, наследующиеся от Field напрямую, переопределяете get_prep_value(), или используете RawSQL, extra(), или raw(), вы должны убедиться, что выполняете необходимое приведение типов.

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

Django поддерживает SQLite 3.7.15 и более поздние версии.

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

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

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

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

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

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

Возможные обходные пути описаны в sqlite.org, но они не используются по умолчанию в бэкенде SQLite в Django, так как их интеграция была бы довольно сложной. Таким образом, Django предоставляет поведение 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 не поддерживается

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

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

Django поддерживает версии сервера баз данных Oracle 12.1 и выше. Требуется версия 5.2 или выше драйвера Python Oracle Database Server 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. В частности, это необходимо для собственного набора тестов 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',

Пример строки полного 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 использует предложение RETURNING INTO, чтобы эффективно получить значение поля AutoField при вставке новых строк. Это поведение может привести к ошибке DatabaseError в некоторых необычных конфигурациях, таких как вставка в удалённую таблицу или в представление с триггером INSTEAD OF. Предложение RETURNING INTO можно отключить, установив параметр use_returning_into конфигурации базы данных на значение False.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • SAP SQL Anywhere
  • IBM DB2
  • Microsoft SQL Server
  • Firebird
  • ODBC

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

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

Spec-Zone.ru

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