Базы данных
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.2 и выше. Он требует использования 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. Если вам нужен более высокий уровень изоляции, например, 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, как это делается с типами поиска contains и startswith.
Операция миграции для добавления расширений
Если вам нужно добавить расширение PostgreSQL (например, hstore, postgis, и т. д.) с помощью миграции, используйте операцию CreateExtension.
Ускорение выполнения тестов с помощью недолговечных настроек
Вы можете ускорить время выполнения тестов, настроив PostgreSQL на недолговечность.
Предупреждение
Это опасно: это сделает вашу базу данных более уязвимой к потере или повреждению данных в случае сбоя сервера или отключения электроэнергии. Используйте только на тестовых машинах, где вы можете легко восстановить все содержимое всех баз данных в кластере.
Примечания по 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 в качестве движка хранения по умолчанию. |
Драйверы API базы данных MySQL
API Python базы данных описан в PEP 249. MySQL имеет три основных драйвера, которые реализуют этот API:
- MySQLdb — это родной драйвер, разработанный и поддерживаемый Энди Дастманом на протяжении более десяти лет.
-
mysqlclient — это вилка
MySQLdb, которая, в частности, поддерживает Python 3 и может использоваться как прямая замена MySQLdb. На момент написания этого документа это **рекомендуемый выбор** для использования MySQL с Django. - MySQL Connector/Python — это чистый Python-драйвер от Oracle, который не требует библиотеки MySQL-клиента или каких-либо Python-модулей за пределами стандартной библиотеки.
Все эти драйверы потокобезопасны и обеспечивают кэширование соединений. MySQLdb — единственный, который в настоящее время не поддерживает Python 3.
Помимо драйвера 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.
Установка 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.
Создание ваших таблиц
При генерации 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 и 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 в миграции данных.
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) на более новую версию с https://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 может обработать в стандартной конфигурации. Эта ошибка означает, что один поток или процесс имеет эксклюзивную блокировку соединения с базой данных, а другой поток ожидал снятия блокировки.
Встроенный в 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 не поддерживает этот стиль.
Примечания по Oracle
Django поддерживает серверы баз данных Oracle версии 11.2 и выше. Поддерживаются версии 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.
Все эти права включены в роль 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.10/ref/databases/