添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Toggle theme (current theme: auto)
Toggle theme (current theme: light)
Toggle theme (current theme: dark)
Toggle Light / Dark / Auto color theme
Toggle theme (current theme: auto)
Toggle theme (current theme: light)
Toggle theme (current theme: dark)
Toggle Light / Dark / Auto color theme

创建数据库

确保你的数据库被配置成能够存储任意字符串数据。通常,这意味着给它一个 UTF-8 或 UTF-16 的编码。如果你使用更严格的编码——例如,latin1(iso8859-1)——你将无法在数据库中存储某些字符,信息将丢失。

  • MySQL 用户,请参考 MySQL 手册 ,了解如何设置或更改数据库字符集编码。
  • PostgreSQL 用户参见 PostgreSQL manual ,了解以正确编码创建数据库的细节。
  • 关于如何设置( 第 2 节 )或改变( 第 11 节 )数据库字符集编码,请参考 Oracle 手册
  • 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 时可能会遇到。框架的国际化特性引入了“惰性翻译”的概念——一个已经被标记为翻译的字符串,但其实际的翻译结果直到该对象被用于字符串时才被确定。这个功能在以下情况下非常有用:在使用字符串之前,翻译的 locale 是未知的,即使该字符串可能是在第一次导入代码时创建的。

    通常情况下,你不必担心惰性翻译的问题。只是要注意,如果你检查一个对象,并且它声称是 django.utils.functional.__proxy__ 对象,它就是一个惰性翻译。调用 str() 作为参数调用 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() 相同。这与 Python 内置的 str() 函数的语义略有不同,但在 Django 内部的一些地方需要区分。
  • 通常,你只需要使用 force_str() 。在任何可能是字符串或字节字符串的输入数据上尽可能早地调用它,从那时起,你可以将结果视为始终是字符串。

    URI 和 IRI 处理

    网络框架必须处理 URL(统一资源定位符,属于IRI的一种)。URL 的要求之一是只使用 ASCII 字符进行编码。然而,在国际环境中,你可能需要从一个 IRI (非常宽泛地说,它是一个可以包含 Unicode 字符的 URI )构造 URL。使用以下函数对 IRI 进行引用和转换为 URI:

  • django.utils.encoding.iri_to_uri() 函数,它实现了 RFC 3987#section-3.1 所要求的从 IRI 到 URI 的转换。
  • 来自 Python 标准库的 urllib.parse.quote() urllib.parse.quote_plus() 函数。
  • 这两组函数的目的略有不同,因此必须将它们区分开来。通常,你会在 IRI 或 URI 路径的个别部分使用 quote() ,这样任何保留的字符如“&”或“%”都会被正确编码。然后,你将 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 实现了从 URI 到 IRI 的转换。

    一个例子来演示:

    >>> 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(即 使用 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)
    

    即使 self.location 是类似于“Jack visited Paris & Orléans”,这个函数也会返回一个正确编码的 URL。(事实上,在上面的例子中,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 文件名。如果你的环境没有正确配置,当保存文件名或内容包含非 ASCII 字符的文件时,你会遇到 UnicodeEncodeError 异常。

    文件系统对 UTF-8 文件名的支持有所不同,可能取决于环境。在交互式 Python shell 中运行检查你当前的配置:

    import sys
    sys.getfilesystemencoding()
    

    这应该输出“UTF-8”。

    LANG 环境变量负责在 Unix 平台上设置预期的编码。请查阅您操作系统和应用服务器的文档,了解设置此变量的适当语法和位置。参考 如何使用 Apache 和 mod_wsgi 托管 Django 获取示例。

    在你的开发环境中,你可能需要向你的 ~.bashrc 添加一个类似的设置:

    export LANG="en_US.UTF-8"
    

    表单提交

    HTML 表单提交是一个棘手的领域。无法保证提交的数据会包含编码信息,这意味着框架可能不得不猜测提交数据的编码。

    Django 采用了一种“惰性”的方式来解码表单数据。HttpRequest 对象中的数据只有在你访问它时才会被解码。事实上,大部分数据根本没有被解码。只有 HttpRequest.GETHttpRequest.POST 数据结构有任何解码应用。这两个字段将作为 Unicode 数据返回其成员。HttpRequest 的所有其他属性和方法将完全按照客户端提交的数据返回。

    默认情况下,DEFAULT_CHARSET 配置被用作表单数据的假定编码。如果你需要为一个特定的表单改变这个配置,你可以在一个 HttpRequest 实例上设置 encoding 属性。例如:

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

    你甚至可以在访问了 request.GETrequest.POST 之后改变编码,所有后续的访问都将使用新的编码。

    大多数开发人员不需要担心更改表单编码,但对于那些与编码无法控制的传统系统对话的应用程序来说,这是一个有用的功能。

    Django 不会对文件上传的数据进行解码,因为这些数据通常被视为字节的集合,而不是字符串。任何自动解码都会改变字节流的含义。