Unicode-data¶
Django stöder Unicode-data överallt.
I det här dokumentet beskrivs vad du behöver veta om du skriver program som använder data eller mallar som är kodade i något annat än ASCII.
Skapa databasen¶
Se till att din databas är konfigurerad för att kunna lagra godtyckliga strängdata. Normalt innebär detta att du ger den en kodning av UTF-8 eller UTF-16. Om du använder en mer restriktiv kodning, t.ex. latin1 (iso8859-1), kan du inte lagra vissa tecken i databasen och information går förlorad.
MySQL-användare, se MySQL manual för detaljer om hur du ställer in eller ändrar databasens teckenuppsättningskodning.
PostgreSQL-användare, se PostgreSQL-manualen för information om hur du skapar databaser med rätt kodning.
Oracle-användare, se Oracle manual för detaljer om hur man ställer in (section 2) eller ändrar (section 11) databasens teckenuppsättningskodning.
SQLite-användare, det finns inget du behöver göra. SQLite använder alltid UTF-8 för intern kodning.
Alla Djangos databasbackends konverterar automatiskt strängar till lämplig kodning för att prata med databasen. De konverterar också automatiskt strängar som hämtas från databasen till strängar. Du behöver inte ens tala om för Django vilken kodning din databas använder: det hanteras transparent.
Mer information finns i avsnittet ”Databas-API:et” nedan.
Allmän stränghantering¶
När du använder strängar med Django - t.ex. i databasuppslagningar, mallrendering eller någon annanstans - har du två val för att koda dessa strängar. Du kan använda vanliga strängar eller bytestrings (som börjar med ett ’b’).
Varning
En bytestring bär inte med sig någon information om dess kodning. Av den anledningen måste vi göra ett antagande, och Django antar att alla bytestrings är i UTF-8.
Om du skickar en sträng till Django som har kodats i något annat format kommer saker och ting att gå fel på intressanta sätt. Vanligtvis kommer Django att höja ett UnicodeDecodeError
vid någon tidpunkt.
Om din kod bara använder ASCII-data är det säkert att använda dina vanliga strängar och skicka runt dem som du vill, eftersom ASCII är en delmängd av UTF-8.
Låt dig inte luras att tro att om inställningen DEFAULT_CHARSET
är satt till något annat än 'utf-8'
så kan du använda den andra kodningen i dina bytestrings! DEFAULT_CHARSET
gäller endast för de strängar som genereras som resultat av mallrendering (och e-post). Django kommer alltid att anta UTF-8-kodning för interna bytestrings. Anledningen till detta är att DEFAULT_CHARSET
-inställningen faktiskt inte är under din kontroll (om du är applikationsutvecklare). Den kontrolleras av den person som installerar och använder din applikation - och om den personen väljer en annan inställning måste din kod fortfarande fungera. Den kan alltså inte förlita sig på den inställningen.
I de flesta fall när Django hanterar strängar kommer den att konvertera dem till strängar innan den gör något annat. Så, som en allmän regel, om du skickar in en bytestring, var beredd på att få en sträng tillbaka i resultatet.
Översatta strängar¶
Bortsett från strängar och bytestrings finns det en tredje typ av strängliknande objekt som du kan stöta på när du använder Django. Ramverkets internationaliseringsfunktioner introducerar konceptet ”lazy translation” - en sträng som har markerats som översatt men vars faktiska översättningsresultat inte bestäms förrän objektet används i en sträng. Denna funktion är användbar i fall där översättningslokalen är okänd tills strängen används, även om strängen ursprungligen kan ha skapats när koden först importerades.
Normalt sett behöver du inte oroa dig för lata översättningar. Var bara medveten om att om du undersöker ett objekt och det påstår sig vara ett django.utils.functional.__proxy__
-objekt, är det en lat översättning. Om du anropar str()
med den lata översättningen som argument kommer en sträng att genereras i den aktuella språkdräkten.
Mer information om lata översättningsobjekt finns i dokumentationen internationalisering.
Användbara funktioner¶
Eftersom vissa strängoperationer dyker upp om och om igen levereras Django med några användbara funktioner som bör göra det lite enklare att arbeta med sträng- och bytestringobjekt.
Omvandlingsfunktioner¶
Modulen django.utils.encoding
innehåller några funktioner som är praktiska för att konvertera fram och tillbaka mellan strängar och bytestrings.
smart_str(s, encoding='utf-8', strings_only=False, errors='strict')
konverterar indata till en sträng. Parameternencoding
anger kodningen för indata. (Django använder till exempel detta internt vid bearbetning av formulärinmatningsdata, som kanske inte är UTF-8-kodade) Parameternstrings_only
, om den sätts till True, kommer att resultera i att Python-tal, booleaner ochNone
inte konverteras till en sträng (de behåller sina ursprungliga typer). Parameternerrors
tar något av de värden som accepteras av Pythons funktionstr()
för dess felhantering.force_str(s, encoding='utf-8', strings_only=False, errors='strict')
är identisk medsmart_str()
i nästan alla fall. Skillnaden är när det första argumentet är en :ref:lazy translation <lazy-translations>`-instans. Medan ``smart_str()
bevarar lata översättningar, tvingarforce_str()
dessa objekt till en sträng (vilket gör att översättningen sker). Normalt sett vill du användasmart_str()
. Menforce_str()
är användbart i malltaggar och filter som absolut måste ha en sträng att arbeta med, inte bara något som kan konverteras till en sträng.smart_bytes(s, encoding='utf-8', strings_only=False, errors='strict')
är i princip motsatsen tillsmart_str()
. Den tvingar det första argumentet till en bytestring. Parameternstrings_only
har samma beteende som försmart_str()
ochforce_str()
. Detta är något annorlunda semantik från Pythons inbyggdastr()
-funktion, men skillnaden behövs på några ställen inom Djangos internals.
Normalt sett behöver du bara använda force_str()
. Anropa den så tidigt som möjligt på alla indata som kan vara antingen en sträng eller en bytestring, och från och med då kan du behandla resultatet som att det alltid är en sträng.
URI- och IRI-hantering¶
Webbramverk måste hantera URL:er (som är en typ av IRI). Ett krav på URL:er är att de kodas med enbart ASCII-tecken. I en internationell miljö kan du dock behöva konstruera en URL från en IRI – mycket löst uttryckt, en URI som kan innehålla Unicode-tecken. Använd dessa funktioner för att citera och konvertera en IRI till en URI:
Funktionen
django.utils.encoding.iri_to_uri()
, som implementerar konverteringen från IRI till URI enligt kraven i RFC 3987 Section 3.1.Funktionerna
urllib.parse.quote()
ochurllib.parse.quote_plus()
från Pythons standardbibliotek.
Dessa två grupper av funktioner har lite olika syften, och det är viktigt att hålla isär dem. Normalt sett använder du quote()
på de enskilda delarna av IRI:n eller URI-sökvägen så att alla reserverade tecken som ’&’ eller ’%’ kodas korrekt. Sedan använder du iri_to_uri()
på hela IRI:n och konverterar alla icke-ASCII-tecken till rätt kodade värden.
Observera
Tekniskt sett är det inte korrekt att säga att iri_to_uri()
implementerar hela algoritmen i IRI-specifikationen. Den utför inte (ännu) den internationella domännamnskodningsdelen av algoritmen.
Funktionen iri_to_uri()
ändrar inte ASCII-tecken som annars är tillåtna i en URL. Så till exempel kodas inte tecknet ’%’ ytterligare när det skickas till iri_to_uri()
. Detta innebär att du kan skicka en fullständig URL till den här funktionen och den kommer inte att röra till frågesträngen eller något liknande.
Ett exempel skulle kunna förtydliga saken:
>>> 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'
Om du tittar noga kan du se att den del som genererades av quote()
i det andra exemplet inte var dubbelciterad när den skickades till iri_to_uri()
. Detta är en mycket viktig och användbar funktion. Det innebär att du kan konstruera din IRI utan att oroa dig för om den innehåller icke-ASCII-tecken och sedan, precis i slutet, anropa iri_to_uri()
på resultatet.
På samma sätt tillhandahåller Django django.utils.encoding.uri_to_iri()
som implementerar konverteringen från URI till IRI enligt RFC 3987 Section 3.2.
Ett exempel för att visa:
>>> 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'
I det första exemplet är UTF-8-tecken inte citerade. I det andra förblir procentkodningarna oförändrade eftersom de ligger utanför det giltiga UTF-8-intervallet eller representerar ett reserverat tecken.
Både funktionerna iri_to_uri()
och uri_to_iri()
är idempotenta, vilket innebär att följande alltid är sant:
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)
Så du kan säkert anropa den flera gånger på samma URI/IRI utan att riskera problem med dubbelkvotering.
Modeller¶
Eftersom alla strängar returneras från databasen som str
-objekt, kommer modellfält som är teckenbaserade (CharField, TextField, URLField, etc.) att innehålla Unicode-värden när Django hämtar data från databasen. Detta är alltid fallet, även om data skulle kunna passa in i en ASCII-bytestring.
Du kan skicka in bytestrings när du skapar en modell eller fyller i ett fält, och Django konverterar det till strängar när det behövs.
Ta hand om get_absolute_url()
¶
Webbadresser kan bara innehålla ASCII-tecken. Om du konstruerar en URL från bitar av data som kan vara icke-ASCII, var noga med att koda resultaten på ett sätt som är lämpligt för en URL. Funktionen reverse()
hanterar detta åt dig automatiskt.
Om du konstruerar en URL manuellt (dvs. inte använder funktionen reverse()
), måste du själv ta hand om kodningen. I det här fallet använder du funktionerna iri_to_uri()
och quote()
som dokumenterades ovan. Till exempel:
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)
Denna funktion returnerar en korrekt kodad URL även om self.location
är något i stil med ”Jack besökte Paris & Orléans”. (I själva verket är anropet iri_to_uri()
inte nödvändigt i exemplet ovan, eftersom alla icke-ASCII-tecken skulle ha tagits bort vid citering i den första raden)
Mallar¶
Använd strängar när du skapar mallar manuellt:
from django.template import Template
t2 = Template("This is a string template.")
Men det vanligaste är att mallar läses från filsystemet. Om dina mallfiler inte lagras med en UTF-8-kodning, justera inställningen TEMPLATES
. Den inbyggda django
-backend tillhandahåller alternativet 'file_charset'
för att ändra den kodning som används för att läsa filer från disken.
Inställningen DEFAULT_CHARSET
styr kodningen av renderade mallar. Den är inställd på UTF-8 som standard.
Filer¶
Om du tänker tillåta användare att ladda upp filer måste du se till att miljön som används för att köra Django är konfigurerad för att fungera med icke-ASCII-filnamn. Om din miljö inte är korrekt konfigurerad kommer du att stöta på UnicodeEncodeError
-undantag när du sparar filer med filnamn eller innehåll som innehåller icke-ASCII-tecken.
Filsystemets stöd för UTF-8-filnamn varierar och kan bero på miljön. Kontrollera din aktuella konfiguration i ett interaktivt Python-skal genom att köra:
import sys
sys.getfilesystemencoding()
Utmatningen bör vara ”UTF-8”.
Miljövariabeln LANG
är ansvarig för att ställa in den förväntade kodningen på Unix-plattformar. I dokumentationen för ditt operativsystem och din applikationsserver finns information om lämplig syntax och plats för att ange den här variabeln. Se Så här använder du Django med Apache och mod_wsgi för exempel.
I din utvecklingsmiljö kan du behöva lägga till en inställning i din ~.bashrc
som motsvarar:
export LANG="en_US.UTF-8"
Inlämning av formulär¶
Inlämning av HTML-formulär är ett knepigt område. Det finns ingen garanti för att inlämningen kommer att innehålla kodningsinformation, vilket innebär att ramverket kan behöva gissa sig till kodningen av inlämnade data.
Django använder ett ”lata” tillvägagångssätt för att avkoda formulärdata. Data i ett HttpRequest
-objekt avkodas endast när du kommer åt det. Faktum är att de flesta data inte avkodas alls. Endast datastrukturerna HttpRequest.GET
och HttpRequest.POST
har någon avkodning tillämpad på dem. Dessa två fält kommer att returnera sina medlemmar som Unicode-data. Alla andra attribut och metoder i HttpRequest
returnerar data exakt som de skickades av klienten.
Som standard används inställningen DEFAULT_CHARSET
som den förmodade kodningen för formulärdata. Om du behöver ändra detta för ett visst formulär kan du ställa in attributet encoding
på en HttpRequest
-instans. Till exempel:
def some_view(request):
# We know that the data must be encoded as KOI8-R (for some reason).
request.encoding = "koi8-r"
...
Du kan till och med ändra kodningen efter att ha använt request.GET
eller request.POST
, och alla efterföljande åtkomster kommer att använda den nya kodningen.
De flesta utvecklare behöver inte bekymra sig om att ändra formulärkodning, men det här är en användbar funktion för applikationer som pratar med äldre system vars kodning du inte kan kontrollera.
Django avkodar inte data från filuppladdningar, eftersom dessa data normalt behandlas som samlingar av bytes, snarare än strängar. Varje automatisk avkodning där skulle ändra betydelsen av strömmen av bytes.