Данные 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
Параметр принимает любое из значений, которые принимаются в Pythonstr()
функции для его обработки ошибок.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:
django.utils.encoding.iri_to_uri()
Функция, которая реализует преобразование из IRI в URI в соответствии с требованиямиRFC 3987 # раздел-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 # раздел-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 не декодирует данные загрузки файлов, потому что эти данные обычно обрабатываются как коллекции байтов, а не строк. Любое автоматическое декодирование изменило бы значение потока байтов.