Django在任何地方都支持Unicode数据。
此文档告诉您,如果编写的应用程序使用的数据或模板不是用ASCII编码的,您需要知道什么。
确保数据库配置为能够存储任意字符串数据。通常,这意味着给它一个utf-8或utf-16编码。如果使用更严格的编码(例如,Latin1(ISO8859-1)),将无法在数据库中存储某些字符,信息将丢失。
mysql用户,参考 MySQL manual 有关如何设置或更改数据库字符集编码的详细信息。
PostgreSQL用户,请参阅 PostgreSQL manual 有关使用正确编码创建数据库的详细信息,请参阅。
Oracle用户,请参阅 Oracle manual 有关如何设置的详细信息 (section 2 或更改 (section 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()
使用惰性转换作为参数将在当前区域设置中生成字符串。
有关惰性翻译对象的详细信息,请参阅 internationalization 文档。
因为一些字符串操作会一次又一次地出现,所以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()
几乎在所有情况下。区别在于第一个参数是 lazy translation 实例。同时 smart_str()
保留懒惰的翻译, force_str()
将这些对象强制为字符串(导致发生转换)。通常,你会想用 smart_str()
. 然而, force_str()
在模板标记和过滤器中非常有用 must 有一个字符串可以使用,而不仅仅是可以转换为字符串的东西。
smart_bytes(s, encoding='utf-8', strings_only=False, errors='strict')
本质上与 smart_str()
. 它将第一个参数强制为bytestring。这个 strings_only
参数的行为与for相同 smart_str()
和 force_str()
. 这与Python的内置语义稍有不同 str()
功能,但在Django内部的一些地方需要差异。
通常,您只需要使用 force_str()
. 在任何可能是字符串或字节串的输入数据上尽早调用它,从那时起,您可以将结果视为始终是字符串。
Web框架必须处理URL(这是IRI的一种类型)。URL的一个要求是仅使用ASCII字符进行编码。但是,在国际环境中,您可能需要从 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()
函数不会更改URL中允许的ASCII字符。因此,例如,当传递给 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()
它根据 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
当Django从数据库中检索数据时,基于字符的对象、模型字段(charfield、textfield、urlfield等)将包含Unicode值。这是 总是 这种情况下,即使数据可以放入一个ASCII字节串。
您可以在创建模型或填充字段时传入字节串,Django将在需要时将其转换为字符串。
get_absolute_url()
¶URL只能包含ASCII字符。如果您是从可能不是ASCII的数据块构造一个URL,请注意以适合于URL的方式对结果进行编码。这个 reverse()
函数自动为您处理此问题。
如果您正在手动构造一个URL(即, not 使用 reverse()
函数),您需要自己处理编码。在这种情况下,使用 iri_to_uri()
和 quote()
记录的功能 above. 例如::
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。
如果您打算允许用户上传文件,则必须确保用于运行Django的环境配置为使用非ASCII文件名。如果您的环境配置不正确,您将遇到 UnicodeEncodeError
使用包含非ASCII字符的文件名或内容保存文件时例外。
文件系统对UTF-8文件名的支持各不相同,可能取决于环境。通过运行以下命令,检查交互式python shell中的当前配置:
import sys
sys.getfilesystemencoding()
这将输出“utf-8”。
这个 LANG
环境变量负责设置Unix平台上的预期编码。有关设置此变量的适当语法和位置,请参阅您的操作系统和应用程序服务器的文档。请参阅 如何将Django与Apache和 mod_wsgi 举个例子。
在开发环境中,可能需要将设置添加到 ~.bashrc
类似于:
export LANG="en_US.UTF-8"
HTML表单提交是一个棘手的领域。无法保证提交内容中包含编码信息,这意味着框架可能必须猜测提交数据的编码。
Django采用“懒惰”的方式对表单数据进行解码。AN中的数据 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不解码文件上载的数据,因为该数据通常被视为字节的集合,而不是字符串。任何自动解码都会改变字节流的含义。
12月 18, 2023