Spec-Zone.ru › Django 1.11

Базы данных

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.3 и выше. Требуется 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.

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

Новое в Django 1.11.

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

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

Новое в Django 1.11.1.

Использование менеджера пулов соединений в режиме пула транзакций (например, 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-запросы для этого.

Шаблоны тестовых баз данных

Новое в Django 1.11.

Вы можете использовать настройку TEST['TEMPLATE'] для указания шаблона (например, 'template0') для создания тестовой базы данных.

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

Вы можете ускорить время выполнения тестов, настроив PostgreSQL для недолговечных данных.

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

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

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

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

Django поддерживает MySQL 5.5.x - 5.7.x. MySQL 8 и более поздние версии не поддерживаются.

Функция 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 в качестве движка хранения по умолчанию.

Драйверы MySQL DB API

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

  • MySQLdb — это драйвер нативного уровня, который развивается и поддерживается Andy Dustman уже более десяти лет.
  • 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.3 или выше.

На момент написания последняя версия MySQLdb (1.2.5) не поддерживает Python 3. Для использования MySQLdb в Python 3 необходимо установить mysqlclient.

Примечание

Существуют известные проблемы с тем, как MySQLdb преобразует строки дат в объекты datetime. В частности, строки дат со значением 0000-00-00 допустимы для MySQL, но MySQLdb преобразует их в None.

Это означает, что следует быть осторожным при использовании loaddata и dumpdata с записями, которые могут иметь значения 0000-00-00, так как они будут преобразованы в None.

mysqlclient

Django поддерживает mysqlclient с версии 1.3.3 по 1.3.13.

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 Character Sets, сравнения для сортировки utf8_general_ci быстрее, но немного менее точны, чем сравнения для utf8_unicode_ci. Если это приемлемо для вашего приложения, вы должны использовать utf8_general_ci, так как она быстрее. Если это неприемлемо (например, если вам требуется немецкий порядок словарей), используйте utf8_unicode_ci, так как она более точна.

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

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

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

Обратитесь к документации по настройкам.

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

  1. OPTIONS.
  2. NAME, USER, PASSWORD, HOST, PORT
  3. Файлы опций MySQL.

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

Вот пример конфигурации, использующей файл опций MySQL:

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file': '/path/to/my.cnf',
        },
    }
}


# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8

Некоторые другие опции подключения MySQLdb могут быть полезными, такие как ssl, init_command, и sql_mode.

Настройка sql_mode

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

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

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

Новое в Django 1.11.

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

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

или None для использования уровня изоляции, настроенного на сервере. Однако Django лучше всего работает с уровнем «read committed», а не с по умолчанию в MySQL «repeatable read». Возможны потери данных при использовании «repeatable read».

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

При генерации схемы 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 в миграции данных.

TIMESTAMP столбцы

Если вы используете старую базу данных, которая содержит TIMESTAMP столбцы, вы должны установить USE_TZ = False для предотвращения повреждения данных. inspectdb сопоставляет эти столбцы с DateTimeField, и если вы включите поддержку часовых поясов, как MySQL, так и Django попытаются преобразовать значения из UTC в местное время.

Блокировка строк с QuerySet.select_for_update()

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

У оболочки 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 не поддерживает это.

Заметки по Oracle

Django поддерживает Oracle Database Server версии 11.2 и выше. Поддерживаются версии Python-драйвера cx_Oracle с 5.2 по 6.4.1.

Для работы команды 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, если в качестве имени поля модели или значения параметра db_column используются определённые ключевые слова Oracle. Django приводит все идентификаторы, используемые в запросах, к кавычкам, чтобы предотвратить большинство подобных проблем, но эта ошибка всё ещё может возникнуть, если тип данных Oracle используется в качестве имени столбца. В частности, будьте осторожны, чтобы не использовать имена date, timestamp, number или float в качестве имени поля.

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

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

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

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

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

Использование сторонней базы данных

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

  • 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/1.11/ref/databases/

Spec-Zone.ru

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