Django admite datos Unicode en todas partes.

Este documento le dice lo que necesita saber si está escribiendo aplicaciones que usan datos o plantillas que están codificadas en algo que no sea ASCII.

Creando la base de datos

Asegúrese de que su base de datos esté configurada para poder almacenar arbitrarias string datos. Normalmente, esto significa darle una codificación de UTF-8 o UTF-16. Si usa una codificación más restrictiva, por ejemplo, latin1 (iso8859-1), no podrá almacenar ciertos caracteres en la base de datos y la información se perderá.

  • Usuarios de MySQL, consulte la Manual de MySQL para obtener detalles sobre cómo configurar o modificar la codificación del juego de caracteres de la base de datos.
  • Usuarios de PostgreSQL, consulte la Manual de PostgreSQL (sección 22.3.2 en PostgreSQL 9) para obtener detalles sobre la creación de bases de datos con la codificación correcta.
  • Usuarios de Oracle, consulte la Manual de Oracle para obtener detalles sobre cómo configurar (sección 2) o alterar (sección 11) la codificación del juego de caracteres de la base de datos.
  • Usuarios de SQLite, no es necesario que hagan nada. SQLite siempre usa UTF-8 para la codificación interna.

Todos los backends de la base de datos de Django convierten automáticamente las cadenas en la codificación adecuada para comunicarse con la base de datos. También convierten automáticamente las cadenas recuperadas de la base de datos en cadenas. Ni siquiera necesita decirle a Django qué codificación usa su base de datos: eso se maneja de manera transparente.

Para obtener más información, consulte la sección “La API de la base de datos” a continuación.

General string manejo

Siempre que use cadenas con Django, por ejemplo, en búsquedas de bases de datos, renderizado de plantillas o en cualquier otro lugar, tiene dos opciones para codificar esas cadenas. Puede usar cadenas normales o cadenas de bytes (comenzando con una ‘b’).

Advertencia

Una cadena de bytes no lleva ninguna información sobre su codificación. Por esa razón, tenemos que hacer una suposición, y Django asume que todas las cadenas de bytes están en UTF-8.

Si pasa un string a Django que ha sido codificado en algún otro formato, las cosas saldrán mal de formas interesantes. Por lo general, Django generará un UnicodeDecodeError en algún momento.

Si su código solo usa datos ASCII, es seguro usar sus cadenas normales, pasándolas a voluntad, porque ASCII es un subconjunto de UTF-8.

No se deje engañar pensando que si su DEFAULT_CHARSET la configuración está establecida en algo diferente a 'utf-8' ¡Puedes usar esa otra codificación en tus cadenas de bytes! DEFAULT_CHARSET solo se aplica a las cadenas generadas como resultado de la representación de la plantilla (y el correo electrónico). Django siempre asumirá la codificación UTF-8 para las cadenas de bytes internas. La razón de esto es que el DEFAULT_CHARSET La configuración no está realmente bajo su control (si es el desarrollador de la aplicación). Está bajo el control de la persona que instala y usa su aplicación, y si esa persona elige una configuración diferente, su código debe seguir funcionando. Ergo, no puede confiar en esa configuración.

En la mayoría de los casos, cuando Django se ocupa de cadenas, las convertirá en cadenas antes de hacer cualquier otra cosa. Entonces, como regla general, si pasa una cadena de bytes, prepárese para recibir una string de vuelta en el resultado.

Cadenas traducidas

Aparte de las cadenas y las cadenas de bytes, existe un tercer tipo de string-objeto similar que puede encontrar al usar Django. Las características de internacionalización del marco introducen el concepto de una “traducción perezosa”, una string que se ha marcado como traducido, pero cuyo resultado de traducción real no se determina hasta que el objeto se utiliza en una string. Esta función es útil en los casos en los que se desconoce la configuración regional de la traducción hasta que string se utiliza, aunque el string podría haberse creado originalmente cuando se importó el código por primera vez.

Normalmente, no tendrá que preocuparse por las traducciones perezosas. Solo tenga en cuenta que si examina un objeto y afirma ser un django.utils.functional.__proxy__ objeto, es una traducción perezosa. Vocación str() con la traducción diferida ya que el argumento generará un string en la localidad actual.

Para obtener más detalles sobre los objetos de traducción diferidos, consulte la internacionalización documentación.

Funciones de utilidad útiles

Porque algunos string las operaciones surgen una y otra vez, Django viene con algunas funciones útiles que deberían hacer trabajar con string y objetos de cadena de bytes un poco más fáciles.

Funciones de conversión

los django.utils.encoding El módulo contiene algunas funciones que son útiles para convertir entre cadenas y cadenas de bytes.

  • smart_str(s, encoding='utf-8', strings_only=False, errors='strict') convierte su entrada en un string. los encoding parámetro especifica la codificación de entrada. (Por ejemplo, Django usa esto internamente cuando procesa datos de entrada de formularios, que pueden no estar codificados en UTF-8). strings_only parámetro, si se establece en True, dará como resultado números de Python, booleanos y None no ser convertido en un string (mantienen sus tipos originales). los errors El parámetro toma cualquiera de los valores que son aceptados por Python str() función para su manejo de errores.
  • force_str(s, encoding='utf-8', strings_only=False, errors='strict') es idéntico a smart_str() en casi todos los casos. La diferencia es cuando el primer argumento es un traducción perezosa ejemplo. Tiempo smart_str() conserva traducciones perezosas, force_str() obliga a esos objetos a string (haciendo que se produzca la traducción). Normalmente, querrás usar smart_str(). Sin embargo, force_str() es útil en etiquetas de plantilla y filtros que absolutamente debe tener un string para trabajar, no solo algo que se pueda convertir en un string.
  • smart_bytes(s, encoding='utf-8', strings_only=False, errors='strict') es esencialmente lo contrario de smart_str(). Fuerza el primer argumento a una cadena de bytes. los strings_only El parámetro tiene el mismo comportamiento que para smart_str() y force_str(). Esta es una semántica ligeramente diferente de la incorporada de Python str() función, pero la diferencia es necesaria en algunos lugares dentro de los componentes internos de Django.

Normalmente, solo necesitará usar force_str(). Llámelo lo antes posible en cualquier dato de entrada que pueda ser un string o una cadena de bytes y, a partir de ese momento, puede tratar el resultado como si fuera siempre un string.

Manejo de URI e IRI

Los frameworks web tienen que lidiar con URL (que son un tipo de IRI). Un requisito de las URL es que estén codificadas utilizando solo caracteres ASCII. Sin embargo, en un entorno internacional, es posible que deba construir una URL a partir de un IRI – hablando muy libremente, un URI que puede contener caracteres Unicode. Utilice estas funciones para citar y convertir un IRI en un URI:

Estos dos grupos de funciones tienen propósitos ligeramente diferentes y es importante mantenerlos en orden. Normalmente, usarías quote() en las porciones individuales de la ruta de IRI o URI para que los caracteres reservados como ‘&’ o ‘%’ estén codificados correctamente. Entonces, aplica iri_to_uri() al IRI completo y convierte cualquier carácter no ASCII a los valores codificados correctos.

Nota

Técnicamente, no es correcto decir que iri_to_uri() implementa el algoritmo completo en la especificación IRI. No realiza (todavía) la parte de codificación del nombre de dominio internacional del algoritmo.

los iri_to_uri() La función no cambiará los caracteres ASCII que de otro modo están permitidos en una URL. Entonces, por ejemplo, el carácter ‘%’ no se codifica más cuando se pasa a iri_to_uri(). Esto significa que puede pasar una URL completa a esta función y no estropeará la consulta. string o algo por el estilo.

Un ejemplo podría aclarar las cosas aquí:

>>>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'

Si observa con atención, puede ver que la porción que fue generada por quote() en el segundo ejemplo no se citó dos veces cuando se pasó a iri_to_uri(). Esta es una característica muy importante y útil. Significa que puede construir su IRI sin preocuparse de si contiene caracteres que no son ASCII y luego, justo al final, llamar iri_to_uri() en el resultado.

Del mismo modo, Django proporciona django.utils.encoding.uri_to_iri() que implementa la conversión de URI a IRI según RFC 3987 # sección-3.2.

Un ejemplo para demostrar:

>>>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'

En el primer ejemplo, los caracteres UTF-8 están sin comillas. En el segundo, las codificaciones porcentuales permanecen sin cambios porque se encuentran fuera del rango UTF-8 válido o representan un carácter reservado.

Ambos iri_to_uri() y uri_to_iri() Las funciones son idempotentes, lo que significa que lo siguiente siempre es true:

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)

Por lo tanto, puede llamarlo de forma segura varias veces en el mismo URI / IRI sin correr el riesgo de problemas de comillas dobles.

Modelos

Debido a que todas las cadenas se devuelven desde la base de datos como str Los objetos, los campos del modelo que se basan en caracteres (CharField, TextField, URLField, etc.) contendrán valores Unicode cuando Django recupere datos de la base de datos. Este es siempre el caso, incluso si los datos pudieran caber en una cadena de bytes ASCII.

Puede pasar cadenas de bytes al crear un modelo o rellenar un campo, y Django lo convertirá en cadenas cuando sea necesario.

Cuidando en get_absolute_url()

Las URL solo pueden contener caracteres ASCII. Si está construyendo una URL a partir de datos que pueden no ser ASCII, tenga cuidado de codificar los resultados de una manera que sea adecuada para una URL. los reverse() La función se encarga de esto automáticamente.

Si está construyendo una URL manualmente (es decir, no utilizando el reverse() función), deberá encargarse de la codificación usted mismo. En este caso, utilice el iri_to_uri() y quote() funciones que se documentaron anteriormente. Por ejemplo:

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

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

Esta función devuelve una URL codificada correctamente incluso si self.location es algo así como “Jack visitó Paris & Orléans”. (De hecho, el iri_to_uri() La llamada no es estrictamente necesaria en el ejemplo anterior, porque todos los caracteres no ASCII se habrían eliminado al citar en la primera línea).

Plantillas

Utilice cadenas al crear plantillas manualmente:

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

Pero el caso común es leer plantillas de la sistema de archivos. Si sus archivos de plantilla no se almacenan con una codificación UTF-8, ajuste la TEMPLATES configuración. El incorporado django backend proporciona el 'file_charset' opción para cambiar la codificación utilizada para leer archivos del disco.

los DEFAULT_CHARSET La configuración controla la codificación de las plantillas renderizadas. Está configurado en UTF-8 de forma predeterminada.

Etiquetas y filtros de plantilla

Un par de consejos para recordar al escribir sus propias etiquetas de plantilla y filtros:

  • Devolver siempre las cadenas de una etiqueta de plantilla render() método y de filtros de plantilla.
  • Usar force_str() en preferencia a smart_str() en estos lugares. La representación de etiquetas y las llamadas de filtro se producen a medida que se representa la plantilla, por lo que no hay ninguna ventaja en posponer la conversión de objetos de traducción diferidos en cadenas. Es más fácil trabajar únicamente con cadenas en ese punto.

Archivos

Si pretende permitir que los usuarios carguen archivos, debe asegurarse de que el entorno utilizado para ejecutar Django esté configurado para funcionar con nombres de archivo que no sean ASCII. Si su entorno no está configurado correctamente, encontrará UnicodeEncodeError excepciones al guardar archivos con nombres de archivo que contienen caracteres no ASCII.

La compatibilidad del sistema de archivos con los nombres de archivo UTF-8 varía y puede depender del entorno. Verifique su configuración actual en un shell de Python interactivo ejecutando:

import sys
sys.getfilesystemencoding()

Esto debería generar “UTF-8”.

los LANG La variable de entorno es responsable de configurar la codificación esperada en plataformas Unix. Consulte la documentación de su sistema operativo y servidor de aplicaciones para conocer la sintaxis y la ubicación adecuadas para establecer esta variable.

En su entorno de desarrollo, es posible que deba agregar una configuración a su ~.bashrc análogo a::

export LANG="en_US.UTF-8"

Envío de formulario

El envío de formularios HTML es un área complicada. No hay garantía de que el envío incluya información de codificación, lo que significa que el marco podría tener que adivinar la codificación de los datos enviados.

Django adopta un enfoque “perezoso” para decodificar datos de formularios. Los datos en un HttpRequest El objeto solo se decodifica cuando accede a él. De hecho, la mayoría de los datos no se decodifican en absoluto. Solo el HttpRequest.GET y HttpRequest.POST a las estructuras de datos se les aplica cualquier decodificación. Esos dos campos devolverán sus miembros como datos Unicode. Todos los demás attributes y métodos de HttpRequest devolver los datos exactamente como los envió el cliente.

Por defecto, el DEFAULT_CHARSET La configuración se utiliza como codificación asumida para los datos del formulario. Si necesita cambiar esto para un formulario en particular, puede configurar el encoding attribute en una HttpRequest ejemplo. Por ejemplo:

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

Incluso puedes cambiar la codificación después de haber accedido request.GET o request.POST, y todos los accesos posteriores utilizarán la nueva codificación.

La mayoría de los desarrolladores no tendrán que preocuparse por cambiar la codificación de formularios, pero esta es una característica útil para aplicaciones que se comunican con sistemas heredados cuya codificación no puede controlar.

Django no decodifica los datos de las cargas de archivos, porque esos datos normalmente se tratan como colecciones de bytes, en lugar de cadenas. Cualquier decodificación automática allí alteraría el significado del flujo de bytes.