Unicode 資料

Django 在任何地方都支援 Unicode 資料。

這份文件告訴您,如果您正在撰寫使用非 ASCII 編碼的資料或範本的應用程式,您需要知道什麼。

建立資料庫

請確保您的資料庫已設定為能夠儲存任意字串資料。通常,這表示給予它 UTF-8 或 UTF-16 的編碼。如果您使用更嚴格的編碼(例如,latin1 (iso8859-1)),您將無法在資料庫中儲存某些字元,並且資訊將會遺失。

  • MySQL 使用者,請參閱 MySQL 手冊,以了解如何設定或變更資料庫字元集編碼的詳細資訊。

  • PostgreSQL 使用者,請參閱 PostgreSQL 手冊,以了解如何建立具有正確編碼的資料庫的詳細資訊。

  • 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.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 參數採用 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 建構 URL – 粗略地說,是可能包含 Unicode 字元的 URI。使用這些函式來引用並將 IRI 轉換為 URI

注意

一個範例可以更清楚地說明

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

一個範例來示範

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

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 上多次呼叫它,而無需擔心雙重引號的問題。

模型

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)

範本

手動建立範本時請使用字串

from django.template import Template

t2 = Template("This is a string template.")

範本標籤和篩選器

撰寫你自己的範本標籤和篩選器時,請記住一些提示:

  • 請務必從範本標籤的 render() 方法和範本篩選器傳回字串。

  • 在這些地方,請優先使用 force_str() 而不是 smart_str()。標籤呈現和篩選器呼叫發生在範本正在呈現時,因此延後將延遲轉換的翻譯物件轉換為字串並沒有優勢。在那時,只使用字串會更容易。

檔案

import sys

sys.getfilesystemencoding()

這應該輸出「UTF-8」。

在你的開發環境中,你可能需要在你的 ~/.bashrc 中新增類似於以下的設定:

export LANG="en_US.UTF-8"

表單提交

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 之後變更編碼,而所有後續的存取都將使用新的編碼。

返回頂部