Данные 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 строку, закодированную в каком-то другом формате, все пойдет не так интересным образом. Обычно UnicodeDecodeErrorв какой-то момент Django вызывает .

Если ваш код использует только данные 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(). Это немного отличается по семантике от встроенной str()функции Python , но разница необходима в нескольких местах внутри Django.

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

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

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

Эти две группы функций имеют несколько разные цели, и важно сохранять их ясность. Обычно вы должны использовать 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 # раздел-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. Если ваша среда настроена неправильно, вы столкнетесь с UnicodeEncodeErrorисключениями при сохранении файлов с именами файлов, которые содержат символы, отличные от ASCII.

Поддержка файловой системой для имен файлов 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 не декодирует данные загрузки файлов, потому что эти данные обычно обрабатываются как коллекции байтов, а не строк. Любое автоматическое декодирование изменило бы значение потока байтов.

Copyright ©2021 All rights reserved