Базы данных
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.0 и выше. Он требует использования psycopg2 2.4.5 или выше (или 2.5+ если вы хотите использовать django.contrib.postgres).
Параметры подключения к 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.
Примечания по MySQL
Поддержка версий
Django поддерживает MySQL 5.5 и выше.
Функция inspectdb Django использует базу данных information_schema, которая содержит подробные данные обо всех схемах баз данных.
Django ожидает, что база данных поддерживает Unicode (кодировка UTF-8) и делегирует ей задачу принудительного выполнения транзакций и ссылочной целостности. Важно понимать, что два последних фактора не на самом деле навязываются MySQL при использовании движка хранения MyISAM, см. следующий раздел.
Движки хранения
MySQL имеет несколько движков хранения. Вы можете изменить движок хранения по умолчанию в конфигурации сервера.
До MySQL 5.5.4 движок хранения по умолчанию был MyISAM [1]. Основные недостатки MyISAM заключаются в том, что он не поддерживает транзакции или принудительное выполнение ограничений внешних ключей. С другой стороны, он был единственным движком, поддерживающим полнотекстовый индексирование и поиск до MySQL 5.6.4.
С MySQL 5.5.5 движком хранения по умолчанию является InnoDB. Этот движок полностью транзакционный и поддерживает ссылки на внешние ключи. Вероятно, это лучший выбор на данный момент. Однако обратите внимание, что счетчик автоинкремента InnoDB теряется при перезагрузке MySQL, потому что он не запоминает значение AUTO_INCREMENT, а вместо этого пересоздаёт его как "max(id)+1". Это может привести к непреднамеренному повторному использованию значений AutoField.
Если вы обновляете существующий проект до MySQL 5.5.5 и затем добавляете некоторые таблицы, убедитесь, что ваши таблицы используют тот же движок хранения (т. е. MyISAM или InnoDB). В частности, если таблицы, имеющие ForeignKey между собой, используют разные движки хранения, вы можете увидеть ошибку, похожую на следующую, при выполнении migrate:
_mysql_exceptions.OperationalError: (
1005, "Can't create table '\\db_name\\.#sql-4a8_ab' (errno: 150)"
)
| [1] | Если это не было изменено пакератором вашего пакета MySQL. Например, у нас были сообщения о том, что установщик Windows Community Server устанавливает InnoDB в качестве движка хранения по умолчанию. |
Драйверы DB API для MySQL
Python Database API описан в PEP 249. Для MySQL существуют три основных драйвера, реализующих этот API:
- MySQLdb — это родной драйвер, который в течение более десяти лет разрабатывался и поддерживался Энди Дастманом.
-
mysqlclient — это форк
MySQLdb, который, в частности, поддерживает Python 3 и может использоваться как прямая замена MySQLdb. На момент написания этой документации это рекомендуемый выбор для использования MySQL с Django. - MySQL Connector/Python — это чистый Python-драйвер от Oracle, который не требует библиотеки MySQL-клиента или каких-либо модулей Python, не входящих в стандартную библиотеку.
Все эти драйверы потокобезопасны и обеспечивают пуллинг подключений. MySQLdb — единственный, который в настоящее время не поддерживает Python 3.
В дополнение к драйверу DB API Django нуждается в адаптере для доступа к драйверам баз данных из своего ORM. Django предоставляет адаптер для MySQLdb/mysqlclient, а MySQL Connector/Python включает свой.
MySQLdb
Django требует версию MySQLdb 1.2.1p2 или выше.
На момент написания последняя версия MySQLdb (1.2.5) не поддерживает Python 3. Чтобы использовать MySQLdb под Python 3, вам нужно установить mysqlclient вместо него.
Примечание
Известны проблемы с тем, как MySQLdb преобразует строки дат в объекты datetime. В частности, строки дат со значением 0000-00-00 являются допустимыми для MySQL, но будут преобразованы в None MySQLdb.
Это означает, что вам следует быть осторожными при использовании loaddata и dumpdata с записями, которые могут иметь 0000-00-00 значения, так как они будут преобразованы в None.
mysqlclient
Django требует mysqlclient версии 1.3.3 или выше. Обратите внимание, что Python 3.2 не поддерживается. За исключением поддержки Python 3.3+, mysqlclient должен в основном вести себя так же, как MySQLDB.
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. Главное, о чем нужно помнить в этом случае, заключается в том, что если вы используете MySQLdb 1.2.2, бэкенд базы данных в Django вернет байтовые строки (а не строки Unicode) для любых текстовых полей, которые он получает из базы данных. Это существенное отличие от обычной практики Django — *всегда* возвращать строки Unicode. Вам, разработчику, необходимо позаботиться о том, что вы будете получать байтовые строки, если вы настроили таблицу(ы) на использование сортировки utf8_bin . Django сам по себе должен работать достаточно стабильно с такими столбцами (кроме таблиц contrib.sessions Session и contrib.admin LogEntry описанных ниже), но ваш код должен быть готов вызывать django.utils.encoding.smart_text() время от времени, если он действительно хочет работать с согласованными данными — Django этого не сделает за вас (слой бэкенда базы данных и слой заполнения модели разделены внутри, поэтому слой базы данных не знает, что ему нужно выполнить это преобразование в этом конкретном случае).
Если вы используете MySQLdb 1.2.1p2, стандартный класс Django CharField вернёт строки Unicode, даже с сортировкой utf8_bin. Однако поля TextField будут возвращены как экземпляр array.array (из стандартного модуля Python array). Django мало что может сделать по этому поводу, так как, опять же, информация, необходимая для выполнения необходимых преобразований, недоступна при чтении данных из базы данных. Эта проблема была исправлена в MySQLdb 1.2.2, поэтому если вы хотите использовать TextField с сортировкой utf8_bin, обновление до версии 1.2.2 и затем работа с байтовыми строками (что не должно быть слишком сложным), как описано выше, является рекомендуемым решением.
Если вы решите использовать сортировку utf8_bin для некоторых ваших таблиц с MySQLdb 1.2.1p2 или 1.2.2, вы по-прежнему должны использовать сортировку utf8_general_ci (по умолчанию) для таблицы django.contrib.sessions.models.Session (обычно называется django_session) и таблицы django.contrib.admin.models.LogEntry (обычно называется django_admin_log). Это две стандартные таблицы, которые используют TextField внутри.
Обратите внимание, что согласно MySQL Unicode Character Sets, сравнения для сортировки utf8_general_ci быстрее, но немного менее корректны, чем сравнения для utf8_unicode_ci. Если это приемлемо для вашего приложения, вы должны использовать utf8_general_ci, потому что она быстрее. Если это неприемлемо (например, если вам требуется немецкий порядок словаря), используйте utf8_unicode_ci, потому что она более точна.
Предупреждение
Формы наборов моделей проверяют уникальные поля в регистрозависимом режиме. Таким образом, при использовании регистронезависимой сортировки набор форм с уникальными значениями поля, отличающимися только регистром, пройдёт проверку, но при вызове save(), будет поднято IntegrityError.
Подключение к базе данных
Обратитесь к документации настроек.
Параметры подключения используются в таком порядке:
Другими словами, если вы установите имя базы данных в OPTIONS, это будет иметь приоритет над NAME, которое, в свою очередь, перекроет все настройки в файле параметров MySQL.
Вот пример конфигурации, использующей файл параметров MySQL:
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'OPTIONS': {
'read_default_file': '/path/to/my.cnf',
},
}
}
# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8
Несколько других параметров подключения MySQLdb могут быть полезны, такие как ssl, init_command, и sql_mode. Для получения дополнительной информации см. документацию MySQLdb.
Создание ваших таблиц
Когда 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 — ресурсоёмкая операция, поэтому нецелесообразно динамически преобразовывать эти методы в недействующие операции на основе результатов такого определения.
Примечания к конкретным полям
Поля символьных данных
Любые поля, хранящиеся с типами столбцов VARCHAR, имеют max_length ограниченные до 255 символов, если вы используете unique=True для поля. Это затрагивает CharField, SlugField и CommaSeparatedIntegerField.
TextField ограничения
MySQL может индексировать только первые N символов столбца типа BLOB или TEXT. Поскольку TextField не имеет определенной длины, вы не можете его отметить как unique=True. MySQL сообщит: «Столбец BLOB/TEXT ‘<db_column>’ используется в спецификации ключа без длины ключа».
Поддержка дробных секунд для полей Time и DateTime
MySQL 5.6.4 и более поздние версии могут хранить дробные секунды, при условии, что определение столбца включает дробную часть (например, DATETIME(6)). Более ранние версии их вообще не поддерживают. Кроме того, в версиях MySQLdb, более ранних 1.2.5, существует ошибка, которая также препятствует использованию дробных секунд с MySQL.
Django не будет обновлять существующие столбцы, чтобы включить дробные секунды, если сервер базы данных их поддерживает. Если вы хотите включить их в существующей базе данных, вам необходимо либо вручную обновить столбец в целевой базе данных, выполнив команду, подобную:
ALTER TABLE `your_table` MODIFY `your_datetime_column` DATETIME(6)
или используя операцию RunSQL в миграции данных.
Ранее Django усекал дробные секунды из значений datetime и time при использовании бэкенда MySQL. Теперь он позволяет базе данных принять решение, нужно ли удалять эту часть значения или нет. По умолчанию новые DateTimeField или TimeField столбцы в MySQL 5.6.4 или более поздних версиях с использованием mysqlclient или MySQLdb 1.2.5 или более поздних версий теперь создаются с поддержкой дробных секунд.
TIMESTAMP столбцы
Если вы используете устаревшую базу данных, содержащую TIMESTAMP столбцы, вы должны установить USE_TZ = False, чтобы избежать повреждения данных. inspectdb сопоставляет эти столбцы с DateTimeField, и если вы включите поддержку часовых поясов, как MySQL, так и Django будут пытаться преобразовать значения из UTC в локальное время.
Блокировка строк с QuerySet.select_for_update()
MySQL не поддерживает опцию NOWAIT для оператора SELECT ... FOR UPDATE. Если select_for_update() используется с nowait=True, будет поднято исключение DatabaseError.
Автоматическое приведение типов может привести к неожиданным результатам
При выполнении запроса к строковому типу, но с целочисленным значением, MySQL приведёт типы всех значений в таблице к целочисленному типу перед выполнением сравнения. Если ваша таблица содержит значения 'abc', 'def', и вы запрашиваете WHERE mycolumn=0, обе строки будут соответствовать. Аналогично, WHERE mycolumn=1 будет соответствовать значению 'abc1'. Поэтому поля строкового типа, включённые в Django, всегда преобразуют значение в строку перед использованием его в запросе.
Если вы реализуете пользовательские поля модели, которые наследуют от Field напрямую, переопределяют get_prep_value() или используют RawSQL, extra() или raw(), убедитесь, что вы выполняете соответствующее приведение типов.
Примечания к SQLite
SQLite предоставляет отличную альтернативу для разработки приложений, в основном ориентированных на чтение или требующих меньшего объёма установки. Однако, как и в случае с другими серверами баз данных, есть некоторые различия, характерные для SQLite, о которых вы должны знать.
Сопоставление подстрок и чувствительность к регистру
Во всех версиях SQLite наблюдается несколько неинтуитивное поведение при попытке сопоставить некоторые типы строк. Это происходит при использовании фильтров iexact или contains в наборах запросов. Поведение делится на два случая:
1. Для сопоставления подстрок все сопоставления выполняются без учёта регистра. Например, фильтр filter(name__contains="aa") будет соответствовать имени "Aabb".
2. Для строк, содержащих символы за пределами ASCII, все точные сопоставления строк выполняются с учётом регистра, даже если в запрос переданы параметры для работы без учёта регистра. Таким образом, фильтр iexact будет вести себя точно так же, как фильтр exact в этих случаях.
Возможные обходные пути описаны на sqlite.org, но они не используются стандартным бэкэндом SQLite в Django, так как их интеграция будет достаточно сложной для надёжного использования. Таким образом, Django демонстрирует стандартное поведение SQLite, и вы должны учитывать это при выполнении фильтрации без учёта регистра или по подстрокам.
Старый SQLite и CASE выражения
SQLite 3.6.23.1 и более ранние версии содержат ошибку при обработке параметров запроса в выражении CASE, содержащем ELSE и арифметику.
SQLite 3.6.23.1 был выпущен в марте 2010 года, и большинство текущих двоичных дистрибутивов для разных платформ включают более новую версию SQLite, за исключением установщиков Python 2.7 для Windows.
На момент написания этой документации последняя версия для Windows — Python 2.7.10 — включает SQLite 3.6.21. Вы можете установить pysqlite2 или заменить sqlite3.dll (установленное по умолчанию в C:\Python27\DLLs) на более новую версию с http://www.sqlite.org/, чтобы исправить эту проблему.
Использование более новых версий драйвера SQLite DB-API 2.0
Django будет использовать модуль pysqlite2 вместо sqlite3, поставляемого с стандартной библиотекой Python, если он доступен.
Это позволяет обновить как интерфейс DB-API 2.0, так и сам SQLite 3 до версий, более новых, чем те, которые включены в вашу конкретную дистрибуцию бинарных файлов Python, при необходимости.
“База данных заблокирована” ошибки
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. Вызов его не повлияет на результат.
“pyformat” стиль параметров в сырых запросах не поддерживается
Для большинства бэкэндов сырые запросы (Manager.raw() или cursor.execute()) могут использовать стиль параметров «pyformat», где заполнитель в запросе задаётся как '%(name)s', а параметры передаются как словарь, а не как список. SQLite не поддерживает это.
Параметры не заключены в кавычки в connection.queries
sqlite3 не предоставляет способ извлечения SQL после цитирования и подстановки параметров. Вместо этого SQL в connection.queries перестраивается с помощью простой интерполяции строк. Это может быть неправильно. Убедитесь, что вы добавляете кавычки, где необходимо, перед копированием запроса в оболочку SQLite.
Примечания по Oracle
Django поддерживает версии сервера баз данных Oracle 11.1 и выше. Поддерживаются версии Python-драйвера cx_Oracle от 4.3.1 до 5.2.1, хотя рекомендуется использовать версии 5.1.3 или выше, так как эти версии поддерживают Python 3.
Обратите внимание, что из-за ошибки повреждения Unicode в cx_Oracle 5.0, эту версию драйвера не следует использовать с Django; ошибка в версии cx_Oracle 5.0.1 устранила эту проблему, поэтому, если вы хотите использовать более новую версию cx_Oracle, используйте версию 5.0.1.
cx_Oracle 5.0.1 или выше можно выборочно скомпилировать с переменной окружения WITH_UNICODE. Это рекомендуется, но не является обязательным.
Для работы команды 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.
До Django 1.8 пользователю тестов предоставлялись роли CONNECT и RESOURCE, поэтому дополнительные права, необходимые для выполнения набора тестов, были другими.
Все эти права включены в роль 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 будет использовать другой дескриптор подключения в зависимости от этого выбора.
Многопотоковый вариант
Если вы планируете запускать 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:
Поддерживаемые версии Django и функции ORM этих неофициальных бэкендов значительно различаются. Запросы относительно конкретных возможностей этих неофициальных бэкендов, а также любые запросы поддержки следует направлять в каналы поддержки, предоставляемые каждым проектом сторонних разработчиков.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.8/ref/databases/