Данные 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. Система интернационализации вводит понятие «отложенный перевод», строка, помеченная как переведенная, но результат перевода которой не определяется до тех пор, пока объект не будет фактически использован как строка. Эта функция полезна в случаях, когда язык перевода неизвестен до момента использования строки, тогда как объект строки может быть изначально создан при первом импорте кода.

Обычно не нужно беспокоиться о задержках перевода. Вы просто должны знать, что если вы исследуете объект, и он идентифицирует себя как объект 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 , предотвращает None преобразование содержимого Python типа number, boolean и в строки (они сохраняют свой базовый тип). Параметр 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 - сокращенно, aURI, содержащий символы Юникода. Используйте эти функции для кодирования и преобразования 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".

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

В вашей среде разработки вам может потребоваться добавить настройку в свой файл ~.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 ©2020 All rights reserved