Djangos mallspråkLink to this heading

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.

MallarLink to this heading

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.

Django template
{% 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 %}

VariablerLink to this heading

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.

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.

FilterLink to this heading

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:

Django template
{{ 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:

Django template
{{ value|length }}

Om värde är ['a', 'b', 'c', 'd'], blir utdata 4.

filstorleksformat

Formaterar värdet som en ”mänskligt läsbar” filstorlek (dvs. '13 KB', '4,1 MB', '102 bytes', etc.). Till exempel:

Django template
{{ value|filesizeformat }}

Om värde är 123456789, skulle utdata vara 117.7 MB.

Återigen, detta är bara några exempel; se inbyggt filter referens för den fullständiga listan.

Du kan också skapa dina egna anpassade mallfilter, se Så här skapar du anpassade malltaggar och filter.

TaggarLink to this heading

Taggar ser ut så här: {% tag %}. Taggar är mer komplexa än variabler: Vissa skapar text i utdata, andra styr flödet genom att utföra loopar eller logik, och vissa laddar in extern information i mallen för att användas av senare variabler.

Vissa taggar kräver en start- och en sluttagg (t.ex. {% tag %} ... taggens innehåll ... {% endtag %}).

Django levereras med ungefär två dussin inbyggda malltaggar. Du kan läsa allt om dem i built-in tag reference. För att ge dig en försmak av vad som finns tillgängligt, här är några av de vanligaste taggarna:

för

Loopa över varje objekt i en array. Till exempel: för att visa en lista över idrottare som finns i athlete_list:

Django template
<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>
if, elif och else

Utvärderar en variabel, och om variabeln är ”true” visas innehållet i blocket:

Django template
{% if athlete_list %}
    Number of athletes: {{ athlete_list|length }}
{% elif athlete_in_locker_room_list %}
    Athletes should be out of the locker room soon!
{% else %}
    No athletes.
{% endif %}

I ovanstående fall, om athlete_list inte är tom, visas antalet deltagare i variabeln {{ athlete_list|length }}. I annat fall, om athlete_in_locker_room_list inte är tom, visas meddelandet ”Athletes should be out…”. Om båda listorna är tomma visas meddelandet ”No athletes.”.

Du kan också använda filter och olika operatorer i if-taggen:

Django template
{% if athlete_list|length > 1 %}
   Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
   Athlete: {{ athlete_list.0.name }}
{% endif %}

Även om exemplet ovan fungerar bör du vara medveten om att de flesta mallfilter returnerar strängar, så matematiska jämförelser med hjälp av filter fungerar i allmänhet inte som du förväntar dig. length är ett undantag.

block och extends

Ställ in mallarv (se nedan), ett kraftfullt sätt att minska ”boilerplate” i mallar.

Återigen, ovanstående är bara ett urval av hela listan; se built-in tag reference för hela listan.

Du kan också skapa dina egna anpassade malltaggar, se Så här skapar du anpassade malltaggar och filter.

KommentarerLink to this heading

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

Django template
{# greeting #}hello

En kommentar kan innehålla vilken mallkod som helst, oavsett om den är ogiltig eller inte. Till exempel:

Django template
{# {% 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 mallLink to this heading

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:

Django template
<!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:

Django template
{% 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:

Django template
<!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 alla base.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 hooks än färre hooks.

  • 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 malltaggen as syntax kan inte användas inuti blocket. Till exempel:, den här mallen renderar ingenting:

    Django template
    {% 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:

    Django template
    {% 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 blocket title:

    Django template
    {% 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-escapingLink to this heading

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:

Django template
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:

Django template
<script>alert('hello')</script>

Med detta namnvärde skulle mallen återges som:

Django template
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?

Html
<b>username

Det skulle resultera i en renderad mall som denna:

Django template
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 &lt;

  • > konverteras till &gt;

  • ' (enkelt citattecken) konverteras till &#x27;

  • " (dubbelcitat) konverteras till &quot;

  • & konverteras till &amp;

Å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 denLink to this heading

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 variablerLink to this heading

Om du vill inaktivera automatisk eskapning för en enskild variabel använder du filtret safe:

Django template
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:

Django template
This will be escaped: &lt;b&gt;
This will not be escaped: <b>

För mallblockLink to this heading

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:

Django template
{% 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:

Django template
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
Django template
{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}
child.html
Django template
{% extends "base.html" %}
{% block title %}This &amp; 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>:

Django template
<h1>This &amp; that</h1>
<b>Hello!</b>

AnteckningarLink to this heading

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 escapingLink to this heading

Som vi nämnde tidigare kan filterargument vara strängar:

Django template
{{ 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 :

Django template
{{ data|default:"3 &lt; 2" }}

…snarare än:

Django template
{{ 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 metodanropLink to this heading

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:

Django template
{% 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:

Django template
{{ task.comment_set.all.count }}

Du kan också få tillgång till metoder som du uttryckligen har definierat i dina egna modeller:

modeller.py
Python
class Task(models.Model):
    def foo(self):
        return "bar"
mall.html
Django template
{{ 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 filterbibliotekLink to this heading

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:

Django template
{% 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:

Django template
{% 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 mallarLink to this heading

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.