Djangos mallspråk¶
Detta dokument förklarar språksyntaxen i Djangos mallsystem. Om du letar efter ett mer tekniskt perspektiv på hur det fungerar och hur du kan utöka det, se Djangos mallspråk: för Python-programmerare.
Djangos mallspråk är utformat för att hitta en balans mellan kraft och enkelhet. Det är utformat för att kännas bekvämt för dem som är vana vid att arbeta med HTML. Om du har någon erfarenhet av andra textbaserade mallspråk, som Smarty eller Jinja2, kommer du att känna dig som hemma med Djangos mallar.
Filosofi
Om du har en bakgrund inom programmering, eller om du är van vid språk som blandar programmeringskod direkt i HTML, bör du komma ihåg att Djangos mallsystem inte bara är Python inbäddat i HTML. Detta är av design: mallsystemet är avsett att uttrycka presentation, inte programlogik.
Djangos mallsystem tillhandahåller taggar som fungerar på samma sätt som vissa programmeringskonstruktioner - en if
-tagg för booleska tester, en for
-tagg för loopning, etc. – men dessa exekveras inte helt enkelt som motsvarande Python-kod, och mallsystemet kommer inte att exekvera godtyckliga Python-uttryck. Endast de taggar, filter och syntax som listas nedan stöds som standard (även om du kan lägga till :doc:``your own extensions </howto/custom-template-tags>` till mallspråket efter behov).
Mallar¶
En mall är en textfil. Den kan generera vilket textbaserat format som helst (HTML, XML, CSV, etc.).
En mall innehåller variabler, som ersätts med värden när mallen utvärderas, och taggar, som styr logiken i mallen.
Nedan visas en minimal mall som illustrerar några grundläggande principer. Varje element kommer att förklaras senare i detta dokument.
{% extends "base_generic.html" %}
{% block title %}{{ section.title }}{% endblock %}
{% block content %}
<h1>{{ section.title }}</h1>
{% for story in story_list %}
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}
Filosofi
Varför använda en textbaserad mall istället för en XML-baserad (som Zope’s TAL)? Vi ville att Djangos mallspråk skulle vara användbart för mer än bara XML/HTML-mallar. Du kan använda mallspråket för vilket textbaserat format som helst, t.ex. e-post, JavaScript och CSV.
Variabler¶
Variabler ser ut på följande sätt: {{variabel }}
. När mallmotorn stöter på en variabel utvärderar den variabeln och ersätter den med resultatet. Variabelnamn består av en kombination av alfanumeriska tecken och understreck ("_"
), men får inte börja med ett understreck eller vara ett tal. Punkten ("."
) förekommer också i variabelavsnitt, men den har en speciell betydelse som beskrivs nedan. Det är viktigt att du inte kan ha mellanslag eller skiljetecken i variabelnamn.
Använd en punkt (.
) för att komma åt attribut för en variabel.
Bakom kulisserna
Tekniskt sett, när mallsystemet stöter på en punkt, försöker det med följande uppslagningar, i denna ordning:
Uppslagning i ordbok
Attribut- eller metoduppslagning
Uppslagning av numeriskt index
Om det resulterande värdet är anropsbart anropas det utan argument. Resultatet av anropet blir mallvärdet.
Denna uppslagningsordning kan orsaka oväntat beteende med objekt som åsidosätter ordboksuppslagning. Tänk till exempel på följande kodavsnitt som försöker loopa över en collections.defaultdict
:
{% for k, v in defaultdict.items %}
Do something with k and v here...
{% endfor %}
Eftersom ordboksuppslagningen sker först, slår detta beteende till och ger ett standardvärde i stället för att använda den avsedda metoden .items()
. I det här fallet bör du överväga att konvertera till en ordbok först.
I exemplet ovan kommer {{ section.title }}
att ersättas med attributet title
för objektet section
.
Om du använder en variabel som inte finns kommer mallsystemet att infoga värdet för alternativet string_if_invalid
, som är inställt på ''
(den tomma strängen) som standard.
Observera att ”bar” i ett malluttryck som {{ foo.bar }}
kommer att tolkas som en bokstavlig sträng och inte som värdet på variabeln ”bar”, om en sådan finns i mallkontexten.
Variabelattribut som börjar med en understrykning kan inte nås eftersom de i allmänhet anses vara privata.
Filter¶
Du kan ändra variabler som ska visas med hjälp av filter.
Filter ser ut så här: {{namn|lower }}
. Här visas värdet för variabeln {{namn }}
efter att ha filtrerats genom filtret lower
, som omvandlar text till gemener. Använd ett rör (|
) för att tillämpa ett filter.
Filter kan ”kedjas” Resultatet från ett filter tillämpas på nästa. {{ text|escape|linebreaks }}
är ett vanligt idiom för att escapa textinnehåll och sedan konvertera radbrytningar till <p>
taggar.
Vissa filter tar emot argument. Ett filterargument ser ut så här: {{ bio|truncatewords:30 }}
. Detta visar de 30 första orden i variabeln bio
.
Filterargument som innehåller mellanslag måste citeras; om du t.ex. vill sammanfoga en lista med kommatecken och mellanslag använder du {{ list|join:", " }}`
.
Django tillhandahåller ett sextiotal inbyggda mallfilter. Du kan läsa allt om dem i inbyggd filterreferens. För att ge dig en försmak av vad som finns tillgängligt, här är några av de vanligaste mallfiltren:
default
Om en variabel är falsk eller tom, använd angiven standard. I annat fall används variabelns värde. Till exempel:
{{ value|default:"nothing" }}
Om
value
inte anges eller är tomt, kommer ovanstående att visa ”nothing
”.längd
Returnerar längden på värdet. Detta fungerar för både strängar och listor. Till exempel:
{{ value|length }}
Om
värde
är['a', 'b', 'c', 'd']
, blir utdata4
.filstorleksformat
Formaterar värdet som en ”mänskligt läsbar” filstorlek (dvs.
'13 KB'
,'4,1 MB'
,'102 bytes'
, etc.). Till exempel:{{ value|filesizeformat }}
Om
värde
är 123456789, skulle utdata vara117.7 MB
.
Återigen, detta är bara några exempel; se :ref:``inbyggt filter referens <ref-templates-builtins-filters>` för den fullständiga listan.
Du kan också skapa dina egna anpassade mallfilter, se Så här skapar du anpassade malltaggar och filter.
Se även
Djangos administratörsgränssnitt kan innehålla en fullständig referens över alla malltaggar och filter som är tillgängliga för en viss webbplats. Se Generatorn för Django-administratörsdokumentation.
Kommentarer¶
Om du vill kommentera bort en del av en rad i en mall använder du kommentarsyntaxen: {# #}
.
Till exempel: skulle den här mallen återges som 'hello'
:
{# greeting #}hello
En kommentar kan innehålla vilken mallkod som helst, oavsett om den är ogiltig eller inte. Till exempel:
{# {% if foo %}bar{% else %} #}
Denna syntax kan endast användas för kommentarer på en rad (inga nya rader tillåts mellan {#
och #}
avgränsarna). Om du behöver kommentera ut en flerradig del av mallen, se taggen comment
.
Arv av mall¶
Den mest kraftfulla - och därmed den mest komplexa - delen av Djangos mallmotor är mallarv. Med mallarv kan du bygga en grundläggande ”skelettmall” som innehåller alla vanliga element på din webbplats och definierar block som barnmallar kan åsidosätta.
Låt oss titta på mallar som ärvs genom att börja med ett exempel:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<title>{% block title %}My amazing site{% endblock %}</title>
</head>
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
Denna mall, som vi kallar base.html
, definierar ett HTML-skelettdokument som du kan använda för en sida med två kolumner. Det är ”barn”-mallarnas uppgift att fylla de tomma blocken med innehåll.
I det här exemplet definierar taggen block
tre block som underordnade mallar kan fylla i. Allt taggen block
gör är att tala om för mallmotorn att en underordnad mall kan åsidosätta dessa delar av mallen.
En barnmall kan se ut så här:
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
{% for entry in blog_entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}
Taggen extends
är nyckeln här. Den talar om för mallmotorn att den här mallen ”förlänger” en annan mall. När mallsystemet utvärderar den här mallen letar det först upp den överordnade mallen - i det här fallet ”base.html”.
Vid den tidpunkten kommer mallmotorn att märka de tre block
-taggarna i base.html
och ersätta dessa block med innehållet i barnmallen. Beroende på värdet på blog_entries
kan utdata se ut som:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<title>My amazing blog</title>
</head>
<body>
<div id="sidebar">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
</div>
<div id="content">
<h2>Entry one</h2>
<p>This is my first entry.</p>
<h2>Entry two</h2>
<p>This is my second entry.</p>
</div>
</body>
</html>
Observera att eftersom barnmallen inte definierade blocket sidebar
används värdet från den överordnade mallen i stället. Innehåll i en {% block %}
-tagg i en överordnad mall används alltid som en fallback.
Du kan använda så många nivåer av arv som behövs. Ett vanligt sätt att använda arv är följande tre nivåer:
Skapa en mall, ”base.html”, som innehåller webbplatsens huvudsakliga utseende och känsla.
Skapa en mall
base_SECTIONNAME.html
för varje ”sektion” på din webbplats. Till exempel:,base_news.html
,base_sports.html
. Dessa mallar utökar allabase.html
och inkluderar sektionsspecifika stilar/design.Skapa individuella mallar för varje typ av sida, t.ex. en nyhetsartikel eller ett blogginlägg. Dessa mallar utökar den lämpliga sektionsmallen.
Detta tillvägagångssätt maximerar återanvändningen av kod och hjälper till att lägga till objekt i delade innehållsområden, t.ex. sektionsomfattande navigering.
Här är några tips för att arbeta med arv:
Om du använder
{% extends %}
i en mall, måste det vara den första malltaggen i den mallen. Mallarv fungerar inte annars.Fler
{% block %}
-taggar i dina basmallar är bättre. Kom ihåg att barnmallar inte behöver definiera alla överordnade block, så du kan fylla i rimliga standardvärden i ett antal block och sedan bara definiera dem du behöver senare. Det är bättre att ha fler krokar än färre krokar.Om du upptäcker att du duplicerar innehåll i ett antal mallar betyder det förmodligen att du bör flytta innehållet till ett
{% block %}
i en överordnad mall.Om du behöver hämta innehållet i blocket från den överordnade mallen kan du använda variabeln
{{ block.super }}
. Detta är användbart om du vill lägga till innehållet i ett överordnat block i stället för att helt åsidosätta det. Data som infogas med hjälp av{{ block.super }}
kommer inte att escapas automatiskt (se nästa avsnitt), eftersom de redan escapats, om nödvändigt, i den överordnade mallen.Genom att använda samma mallnamn som du ärver från, kan
{% extends %}
användas för att ärva en mall samtidigt som du åsidosätter den. Kombinerat med{{ block.super }}
kan detta vara ett kraftfullt sätt att göra små anpassningar. Se Utöka en åsidosatt mall i Overriding templates How-to för ett fullständigt exempel.Variabler som skapas utanför en
{% block %}
med hjälp av malltaggenas
syntax kan inte användas inuti blocket. Till exempel:, den här mallen renderar ingenting:{% translate "Title" as title %} {% block content %}{{ title }}{% endblock %}
För extra läsbarhet kan du välja att ge ett namn till din tagg
{% endblock %}
. Till exempel:{% block content %} ... {% endblock content %}
I större mallar hjälper den här tekniken dig att se vilka
{% block %}
-taggar som stängs.{% block %}
-taggar utvärderas först. Det är därför som innehållet i ett block alltid åsidosätts, oavsett sanningshalten i omgivande taggar. Till exempel: kommer den här mallen alltid att åsidosätta innehållet i blockettitle
:{% if change_title %} {% block title %}Hello!{% endblock title %} {% endif %}
Slutligen bör du notera att du inte kan definiera flera block
-taggar med samma namn i samma mall. Denna begränsning finns eftersom en block-tagg fungerar i ”båda” riktningarna. Det vill säga, en block-tagg ger inte bara ett hål att fylla - den definierar också det innehåll som fyller hålet i föräldern. Om det fanns två block
-taggar med liknande namn i en mall, skulle mallens förälder inte veta vilket av blockens innehåll som skulle användas.
Automatisk HTML-escaping¶
När HTML genereras från mallar finns det alltid en risk att en variabel innehåller tecken som påverkar den resulterande HTML:en. Tänk till exempel på detta mallfragment:
Hello, {{ name }}
Till en början verkar detta vara ett harmlöst sätt att visa en användares namn, men tänk på vad som skulle hända om användaren skrev in sitt namn så här:
<script>alert('hello')</script>
Med detta namnvärde skulle mallen återges som:
Hello, <script>alert('hello')</script>
…vilket innebär att webbläsaren skulle visa en JavaScript-varningsruta!
Och om namnet innehåller symbolen '<'
, så här?
<b>username
Det skulle resultera i en renderad mall som denna:
Hello, <b>username
…vilket i sin tur skulle leda till att resten av webbsidan skulle vara i fetstil!
Det är uppenbart att man inte ska lita blint på data som skickas in av användare och infoga dem direkt i webbsidorna, eftersom en illvillig användare kan använda den här typen av hål för att göra potentiellt dåliga saker. Den här typen av säkerhetsbrist kallas för en XSS-attack (Cross Site Scripting).
För att undvika detta problem har du två alternativ:
Ett, du kan se till att köra varje opålitlig variabel genom
escape
-filtret (dokumenterat nedan), som konverterar potentiellt skadliga HTML-tecken till oskadliga. Detta var standardlösningen i Django under de första åren, men problemet är att det lägger ansvaret på * dig*, utvecklaren / mallförfattaren, att se till att du escapar allt. Det är lätt att glömma att undkomma data.För det andra kan du dra nytta av Djangos automatiska HTML-escaping. Resten av detta avsnitt beskriver hur automatisk eskapning fungerar.
Som standard i Django escapar varje mall automatiskt utdata från varje variabel tagg. Specifikt är dessa fem tecken escapade:
<
konverteras till<`
>
konverteras till>
'
(enkelt citattecken) konverteras till'
"
(dubbelcitat) konverteras till"
&
konverteras till&
Återigen betonar vi att detta beteende är aktiverat som standard. Om du använder Djangos mallsystem är du skyddad.
Så här stänger du av den¶
Om du inte vill att data ska förslutas automatiskt, per webbplats, per mall eller per variabel, kan du stänga av det på flera olika sätt.
Varför skulle du vilja stänga av det? För att mallvariabler ibland innehåller data som du menar ska återges som rå HTML, och då vill du inte att deras innehåll ska escapas. Du kanske till exempel lagrar en HTML-blobb i din databas och vill bädda in den direkt i din mall. Eller så kanske du använder Djangos mallsystem för att producera text som inte är HTML - som ett e-postmeddelande, till exempel.
För enskilda variabler¶
Om du vill inaktivera automatisk eskapning för en enskild variabel använder du filtret safe
:
This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}
Tänk på safe som en förkortning för safe from further escaping eller can be safely interpreted as HTML. I detta exempel, om data
innehåller '<b>'
, kommer utdata att vara:
This will be escaped: <b>
This will not be escaped: <b>
För mallblock¶
För att styra automatisk avstavning för en mall, linda in mallen (eller en viss del av mallen) i autoescape
taggen, så här:
{% autoescape off %}
Hello {{ name }}
{% endautoescape %}
Taggen autoescape
tar antingen on
eller off
som sitt argument. Ibland kanske du vill tvinga fram automatisk eskapning när den annars skulle vara inaktiverad. Här är ett exempel på en mall:
Auto-escaping is on by default. Hello {{ name }}
{% autoescape off %}
This will not be auto-escaped: {{ data }}.
Nor this: {{ other_data }}
{% autoescape on %}
Auto-escaping applies again: {{ name }}
{% endautoescape %}
{% endautoescape %}
Auto-escaping-taggen överför sin effekt till mallar som utökar den aktuella samt mallar som inkluderas via taggen include
, precis som alla blocktaggar. Till exempel:
bas.html
¶{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}
child.html
¶{% extends "base.html" %}
{% block title %}This & that{% endblock %}
{% block content %}{{ greeting }}{% endblock %}
Eftersom auto-escaping är avstängt i basmallen kommer det också att vara avstängt i underordnad mall, vilket resulterar i följande renderade HTML när variabeln greeting
innehåller strängen Hello<b>!</b>
:
<h1>This & that</h1>
<b>Hello!</b>
Anteckningar¶
Generellt sett behöver mallförfattare inte oroa sig för automatisk escaping särskilt mycket. Utvecklare på Python-sidan (personer som skriver vyer och anpassade filter) måste tänka på de fall där data inte ska escapas och markera data på lämpligt sätt, så att saker och ting bara fungerar i mallen.
Om du skapar en mall som kan användas i situationer där du inte är säker på om automatisk eskapning är aktiverad, lägg då till ett escape
-filter till alla variabler som behöver eskapas. När automatisk eskapning är aktiverad finns det ingen risk för att filtret escape
dubbel-eskapar data - filtret escape
påverkar inte variabler med automatisk eskapning.
Stränglitteraler och automatisk escaping¶
Som vi nämnde tidigare kan filterargument vara strängar:
{{ data|default:"This is a string literal." }}
Alla stränglitteraler infogas utan någon automatisk escaping i mallen - de fungerar som om de alla hade passerat genom filtret safe
. Anledningen till detta är att mallförfattaren har kontroll över vad som läggs in i stränglitalen, så att de kan se till att texten är korrekt escapad när mallen skrivs.
Detta innebär att du skulle skriva :
{{ data|default:"3 < 2" }}
…snarare än:
{{ data|default:"3 < 2" }} {# Bad! Don't do this. #}
Detta påverkar inte vad som händer med data som kommer från själva variabeln. Variabelns innehåll escapas fortfarande automatiskt, om det behövs, eftersom det ligger utanför mallförfattarens kontroll.
Tillgång till metodanrop¶
De flesta metodanrop som är kopplade till objekt är också tillgängliga från mallar. Detta innebär att mallar har tillgång till mycket mer än bara klassattribut (som fältnamn) och variabler som skickas in från vyer. Till exempel: tillhandahåller Django ORM ”entry_set” syntax för att hitta en samling objekt som är relaterade till en främmande nyckel. Därför kan du, med en modell som heter ”comment” med en främmande nyckelrelation till en modell som heter ”task”, slingra dig genom alla kommentarer som är kopplade till en viss uppgift så här:
{% for comment in task.comment_set.all %}
{{ comment }}
{% endfor %}
På samma sätt tillhandahåller QuerySets en count()
-metod för att räkna antalet objekt som de innehåller. Därför kan du få en räkning av alla kommentarer som är relaterade till den aktuella uppgiften med:
{{ task.comment_set.all.count }}
Du kan också få tillgång till metoder som du uttryckligen har definierat i dina egna modeller:
modeller.py
¶class Task(models.Model):
def foo(self):
return "bar"
mall.html
¶{{ task.foo }}
Eftersom Django avsiktligt begränsar mängden logisk bearbetning som är tillgänglig i mallspråket är det inte möjligt att skicka argument till metodanrop som nås från mallar. Data bör beräknas i vyer och sedan skickas till mallar för visning.
Anpassade tagg- och filterbibliotek¶
Vissa applikationer tillhandahåller anpassade tagg- och filterbibliotek. För att komma åt dem i en mall, se till att applikationen finns i INSTALLED_APPS
(vi lägger till 'django.contrib.humanize'
i det här exemplet), och använd sedan load
-taggen i en mall:
{% load humanize %}
{{ 45000|intcomma }}
I ovanstående laddar load
taggen taggbiblioteket humanize
, som sedan gör filtret intcomma
tillgängligt för användning. Om du har aktiverat django.contrib.admindocs
kan du läsa dokumentationsområdet i din admin för att hitta listan över anpassade bibliotek i din installation.
Taggen load
kan innehålla flera biblioteksnamn, åtskilda med mellanslag. Exempel på detta:
{% load humanize i18n %}
Se Så här skapar du anpassade malltaggar och filter för information om hur du skriver dina egna anpassade mallbibliotek.
Anpassade bibliotek och arv av mallar¶
När du laddar ett anpassat tagg- eller filterbibliotek görs taggarna/filtren endast tillgängliga för den aktuella mallen - inte för eventuella överordnade eller underordnade mallar längs mallens arvsstig.
Om t.ex. en mall foo.html
har {% load humanize %}
, kommer en underordnad mall (t.ex. en som har {% extends "foo.html" %}
) inte att ha tillgång till humanize-mallens taggar och filter. Den underordnade mallen är ansvarig för sin egen {% load humanize %}
.
Detta är en funktion för underhållbarhetens och sanitetens skull.
Se även
- Mallreferensen
Omfattar inbyggda taggar, inbyggda filter, användning av ett alternativt mallspråk och mycket mer.