Spec-Zone.ru › Django 5.0

Данные Unicode

Django поддерживает данные Unicode везде.

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

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

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

  • Пользователи MySQL, обратитесь к руководству MySQL для получения подробностей о настройке или изменении кодировки набора символов базы данных.
  • Пользователи PostgreSQL, обратитесь к руководству PostgreSQL для получения подробностей о создании баз данных с правильной кодировкой.
  • Пользователи 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. Обратитесь к документации вашей операционной системы и прикладного сервера для соответствующего синтаксиса и расположения для установки этой переменной. См. Как использовать Django с Apache и mod_wsgi для примеров.

В вашей среде разработки вам, возможно, потребуется добавить настройку в ваш ~.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/5.0/ref/unicode/

Spec-Zone.ru

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