Spec-Zone.ru › Django 3.0

Данные Unicode

Django поддерживает данные Unicode повсюду.

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

Создание базы данных

Убедитесь, что ваша база данных настроена для хранения произвольных строковых данных. Обычно это означает использование кодировки UTF-8 или UTF-16. Если вы используете более ограничительную кодировку, например, latin1 (iso8859-1), вы не сможете сохранить определенные символы в базе данных, и информация будет потеряна.

  • Пользователи MySQL, обратитесь к руководству MySQL для получения подробной информации о том, как установить или изменить кодировку набора символов базы данных.
  • Пользователи PostgreSQL, обратитесь к руководству PostgreSQL (раздел 22.3.2 в PostgreSQL 9) для получения подробной информации о создании баз данных с правильной кодировкой.
  • Пользователи Oracle, обратитесь к руководству Oracle для получения подробной информации о том, как установить (раздел 2) или изменить (раздел 11) кодировку набора символов базы данных.
  • Пользователям SQLite ничего делать не нужно. SQLite всегда использует UTF-8 для внутренней кодировки.

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

Для получения дополнительной информации см. раздел «API базы данных» ниже.

Общая обработка строк

Всякий раз, когда вы используете строки с Django — например, при поиске в базе данных, рендеринге шаблонов или в других местах — у вас есть два варианта кодировки этих строк. Вы можете использовать обычные строки или байтовые строки (начинающиеся с ‘b’).

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

Байтовая строка не содержит никакой информации о своей кодировке. По этой причине нам нужно сделать предположение, и Django предполагает, что все байтовые строки находятся в UTF-8.

Если вы передадите строку в Django, которая была закодирована в другом формате, возникнут проблемы. Обычно Django поднимет UnicodeDecodeError в какой-то момент.

Если ваш код использует только данные ASCII, безопасно использовать ваши обычные строки, передавая их по желанию, так как ASCII является подмножеством UTF-8.

Не думайте, что если ваше значение настройки DEFAULT_CHARSET установлено на значение, отличное от 'utf-8', вы можете использовать эту другую кодировку в своих байтовых строках! DEFAULT_CHARSET применяется только к строкам, сгенерированным в результате рендеринга шаблонов (и электронной почты). Django всегда будет предполагать кодировку UTF-8 для внутренних байтовых строк. Причина в том, что значение настройки DEFAULT_CHARSET фактически не под вашим контролем (если вы разработчик приложения). Оно находится под контролем человека, устанавливающего и использующего ваше приложение, и если этот человек выберет другое значение, ваш код все равно должен продолжать работать. Следовательно, он не может полагаться на это значение.

В большинстве случаев, когда Django работает со строками, он преобразует их в строки перед выполнением каких-либо других действий. Таким образом, как общее правило, если вы передаёте байтовую строку, будьте готовы получить строку обратно в результате.

Переведенные строки

Помимо строк и байтовых строк, есть третий тип строкоподобных объектов, с которыми вы можете столкнуться при использовании Django. Функции интернационализации фреймворка вводят понятие «отложенный перевод» — строки, помеченные как переведенные, но фактический результат перевода определяется только при использовании объекта в строке. Эта функция полезна в тех случаях, когда локаль перевода неизвестна до использования строки, даже если строка была первоначально создана при первом импорте кода.

Обычно вам не нужно беспокоиться об отложенных переводах. Просто имейте в виду, что если вы изучите объект, и он заявит, что является объектом django.utils.functional.__proxy__, это отложенный перевод. Вызов str() с отложенным переводом в качестве аргумента сгенерирует строку в текущей локали.

Для получения дополнительной информации об объектах отложенного перевода см. документацию по интернационализации.

Полезные служебные функции

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

Функции преобразования

Модуль django.utils.encoding содержит несколько функций, которые удобны для преобразования между строками и байтовыми строками.

  • smart_str(s, encoding='utf-8', strings_only=False, errors='strict') преобразует свой вход в строку. Параметр encoding указывает кодировку входных данных. (Например, Django использует это при обработке данных ввода формы, которые могут быть закодированы не в UTF-8.) Параметр strings_only, если установлен в значение True, приведет к тому, что числа Python, булевы значения и None не будут преобразованы в строку (они сохранят свои исходные типы). Параметр errors принимает любые значения, которые принимаются функцией Python str() для обработки ошибок.
  • force_str(s, encoding='utf-8', strings_only=False, errors='strict') идентичен smart_str() почти во всех случаях. Разница заключается в том, когда первый аргумент является экземпляром отложенного перевода. В то время как smart_str() сохраняет отложенные переводы, force_str() принудительно преобразует эти объекты в строку (вызывая перевод). Обычно вы захотите использовать smart_str(). Однако force_str() полезна в тегах и фильтрах шаблонов, которые обязательно должны работать со строкой, а не с чем-то, что может быть преобразовано в строку.
  • smart_bytes(s, encoding='utf-8', strings_only=False, errors='strict') по существу противоположна smart_str(). Она принудительно преобразует первый аргумент в байтовую строку. Параметр strings_only имеет такое же поведение, как для smart_str() и force_str(). Это немного отличается от семантики встроенной функции Python str() , но это необходимо в нескольких местах внутри Django.

Обычно вам нужно будет использовать только force_str(). Вызовите его как можно раньше для любых входных данных, которые могут быть либо строкой, либо байтовой строкой, и после этого вы можете рассматривать результат как всегда строку.

Обработка URI и IRI

Веб-фреймворки должны работать с URL-адресами (которые являются типом IRI). Одно из требований к URL-адресам заключается в том, что они кодируются только символами ASCII. Однако в международной среде вам может потребоваться создать URL-адрес из IRI — грубо говоря, URI, который может содержать символы Unicode. Используйте эти функции для цитирования и преобразования IRI в URI:

  • Функция django.utils.encoding.iri_to_uri(), которая реализует преобразование из IRI в URI, как требуется в RFC 3987#section-3.1.
  • Функции urllib.parse.quote() и urllib.parse.quote_plus() из стандартной библиотеки Python.

Эти две группы функций имеют немного разные цели, и важно их различать. Обычно вы будете использовать quote() для отдельных частей пути IRI или URI, чтобы любые служебные символы, такие как ‘&’ или ‘%’, были правильно закодированы. Затем вы применяете iri_to_uri() к полному IRI, и он преобразует все символы, не являющиеся ASCII, в правильные закодированные значения.

Примечание

Технически неверно утверждать, что iri_to_uri() реализует весь алгоритм в спецификации IRI. Она не (еще) выполняет международную часть кодирования доменных имён.

Функция iri_to_uri() не изменит символы ASCII, которые в противном случае разрешены в URL-адресе. Таким образом, например, символ ‘%’ не кодируется дополнительно при передаче в iri_to_uri(). Это означает, что вы можете передать полный URL-адрес в эту функцию, и она не испортит строку запроса или что-либо подобное.

Пример может прояснить ситуацию:

>>> from urllib.parse import quote
>>> from django.utils.encoding import iri_to_uri
>>> quote('Paris & Orléans')
'Paris%20%26%20Orl%C3%A9ans'
>>> iri_to_uri('/favorites/François/%s' % quote('Paris & Orléans'))
'/favorites/Fran%C3%A7ois/Paris%20%26%20Orl%C3%A9ans'

Если вы внимательно посмотрите, вы увидите, что часть, сгенерированная quote() во втором примере, не была заключена в двойные кавычки при передаче в iri_to_uri() . Это очень важная и полезная функция. Она означает, что вы можете сформировать свой IRI, не беспокоясь о том, содержит ли он символы, не являющиеся ASCII, а затем в самом конце вызовите iri_to_uri() на результате.

Аналогично, Django предоставляет django.utils.encoding.uri_to_iri(), которая реализует преобразование из URI в IRI в соответствии с RFC 3987#section-3.2.

Пример для демонстрации:

>>> from django.utils.encoding import uri_to_iri
>>> uri_to_iri('/%E2%99%A5%E2%99%A5/?utf8=%E2%9C%93')
'/♥♥/?utf8=✓'
>>> uri_to_iri('%A9hello%3Fworld')
'%A9hello%3Fworld'

В первом примере символы UTF-8 не заключены в кавычки. Во втором проценты кодировок остаются неизменными, потому что они лежат за пределами допустимого диапазона UTF-8 или представляют собой зарезервированный символ.

Обе функции iri_to_uri() и uri_to_iri() являются идемпотентными, что означает, что следующее всегда верно:

iri_to_uri(iri_to_uri(some_string)) == iri_to_uri(some_string)
uri_to_iri(uri_to_iri(some_string)) == uri_to_iri(some_string)

Поэтому вы можете безопасно вызывать его несколько раз на одном URI/IRI, не рискуя проблемами с двойной цитатой.

Модели

Поскольку все строки возвращаются из базы данных как объекты str, поля модели, основанные на символах (CharField, TextField, URLField и т.д.), будут содержать значения Unicode, когда Django извлекает данные из базы данных. Это всегда так, даже если данные могли бы поместиться в строку байтов ASCII.

Вы можете передавать строки байтов при создании модели или заполнении поля, и Django преобразует их в строки, когда это необходимо.

Обработка get_absolute_url()

URL могут содержать только символы ASCII. Если вы создаёте URL из фрагментов данных, которые могут быть не-ASCII, будьте внимательны, кодируя результаты способом, подходящим для URL. Функция reverse() автоматически обрабатывает это за вас.

Если вы создаёте URL вручную (т.е., не используете функцию reverse()), вам нужно будет позаботиться о кодировании самостоятельно. В этом случае используйте функции iri_to_uri() и quote(), которые были описаны выше. Например:

from urllib.parse import quote
from django.utils.encoding import iri_to_uri

def get_absolute_url(self):
    url = '/person/%s/?x=0&y=0' % quote(self.location)
    return iri_to_uri(url)

Эта функция возвращает правильно закодированный URL, даже если self.location — что-то вроде «Джек посетил Париж и Орлеан». (На самом деле, вызов iri_to_uri() строго не нужен в приведенном выше примере, потому что все символы, не являющиеся ASCII, были удалены при цитировании в первой строке.)

Шаблоны

Используйте строки при ручном создании шаблонов:

from django.template import Template
t2 = Template('This is a string template.')

Но в распространённом случае шаблоны считываются из файловой системы. Если ваши файлы шаблонов не хранятся с кодировкой UTF-8, настройте параметр TEMPLATES. Встроенный бэкенд django предоставляет параметр 'file_charset' для изменения кодировки, используемой для чтения файлов с диска.

Параметр DEFAULT_CHARSET управляет кодировкой рендеренных шаблонов. По умолчанию он установлен в UTF-8.

Тэги и фильтры шаблонов

Несколько советов, которые следует помнить при написании собственных тэгов и фильтров шаблонов:

  • Всегда возвращайте строки из метода render() тэга шаблона и из фильтров шаблонов.
  • Используйте force_str() вместо smart_str() в этих местах. Рендеринг тэгов и вызовы фильтров происходят по мере рендеринга шаблона, поэтому нет преимуществ в отсрочке преобразования объектов ленивого перевода в строки. В этот момент проще работать только со строками.

Файлы

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

Поддержка файловой системы для имён файлов UTF-8 варьируется и может зависеть от среды. Проверьте текущую конфигурацию в интерактивной оболочке Python, выполнив:

import sys
sys.getfilesystemencoding()

Это должно вывести «UTF-8».

Переменная среды LANG отвечает за установку ожидаемой кодировки на платформах Unix. Обратитесь к документации вашей операционной системы и веб-сервера для получения соответствующего синтаксиса и местоположения для установки этой переменной.

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

export LANG="en_US.UTF-8"

Отправка форм

Отправка HTML-форм — сложная область. Нет гарантии, что отправка будет включать информацию о кодировке, что означает, что фреймворк может попытаться угадать кодировку отправленных данных.

Django использует «ленивый» подход к декодированию данных формы. Данные в объекте HttpRequest декодируются только при доступе к ним. На самом деле, большая часть данных вообще не декодируется. Только структуры данных HttpRequest.GET и HttpRequest.POST имеют применённое к ним декодирование. Эти два поля вернут свои члены как данные Unicode. Все другие атрибуты и методы HttpRequest возвращают данные точно так, как они были отправлены клиентом.

По умолчанию, параметр DEFAULT_CHARSET используется в качестве предполагаемой кодировки для данных формы. Если вам нужно изменить это для конкретной формы, вы можете установить атрибут encoding в экземпляре HttpRequest. Например:

def some_view(request):
    # We know that the data must be encoded as KOI8-R (for some reason).
    request.encoding = 'koi8-r'
    ...

Вы даже можете изменить кодировку после доступа к request.GET или request.POST, и все последующие обращения будут использовать новую кодировку.

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

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

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

Spec-Zone.ru

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