Template模板

 目標 css

  • 模板介紹
  • 模板變量
  • 經常使用標籤
  • 經常使用過濾器
  • 自定義過濾器
  • 模板結構
  • 加載靜態文件

 

一 模板介紹  

  在以前的章節中,視圖函數只是直接返回文本,而在實際生產環境中其實不多這樣用,由於實際的頁面大可能是帶有樣式的HTML代碼,這可讓瀏覽器渲染出很是漂亮的頁面。目前市面上有很是多的模板系統,其中最知名最好用的就是DTLJinja2。DTL是Django Template Language三個單詞的縮寫,也就是Django自帶的模板語言。固然也能夠配置Django支持Jinja2等其餘模板引擎,可是做爲Django內置的模板語言,和Django能夠達到無縫銜接而不會產生一些不兼容的狀況。所以建議你們學習好DTL。html

 

 

1-1 DTL與普通的HTML文件的區別

  DTL模板是一種帶有特殊語法的HTML文件,這個HTML文件能夠被Django編譯,能夠傳遞參數進去,實現數據動態化。在編譯完成後,生成一個普通的HTML文件,而後發送給客戶端。前端

 

1-2 渲染模板

  渲染模板有多種方式。這裏講下兩種經常使用的方式。python

  • render_to_string:找到模板,而後將模板編譯後渲染成Python的字符串格式。最後再經過HttpResponse類包裝成一個HttpResponse對象返回回去。示例代碼以下:
from django.template.loader import render_to_string
from django.http import HttpResponse
def book_detail(request,book_id):
     html = render_to_string("detail.html")
     return HttpResponse(html)  
  • render:django 提供了一個更加簡便的方式,直接將模板渲染成字符串和包裝成HttpResponse對象一步到位完成。示例代碼以下
from django.shortcuts import render
def book_list(request):
    return render(request,'list.html')

 

1-3 模版查找路徑

  在項目的settings.py文件中。有一個TEMPLATES配置,這個配置包含了模板引擎的配置,模板查找路徑的配置,模板上下文的配置等。模板路徑能夠在兩個地方配置。django

  • DIRS:這是一個列表,在這個列表中能夠存放全部的模板路徑,之後在視圖中使用render或者render_to_string渲染模板的時候,會在這個列表的路徑中查找模板
  • APP_DIRS:默認爲True,這個設置爲True後,會在INSTALLED_APPS的安裝了的APP下的templates文件加中查找模板。

查找順序 編程

  好比代碼render('list.html')。瀏覽器

  一、先會在DIRS這個列表中依次查找路徑下有沒有這個模板,若是有,就返回。安全

  二、若是DIRS列表中全部的路徑都沒有找到,那麼會先檢查當前這個視圖所處的app是否已經安裝,若是已經安裝了,那麼就先在當前這個app下的templates文件夾中查找模板,若是沒有找到,那麼會在其餘已經安裝了的app中查找。若是全部路徑下都沒有找到,那麼會拋出一個TemplateDoesNotExist的異常。app

 

二 模板變量

1. 在模版中使用變量,須要將變量放到`{{ 變量 }}`中。
2. 若是想要訪問對象的屬性,那麼能夠經過`對象.屬性名`來進行訪問。dom

class Person(object):
    def __init__(self,username):
        self.username = username

context = {
    'person': p
}

  想要訪問`person`類中的`username`屬性,那麼就是經過`person.username`來訪問。

3. 若是想要訪問一個字典的key對應的value,那麼只能經過`字典.key`的方式進行訪問,不能經過`中括號[]`的形式進行訪問。

context = {
    'person': {
        'username':'zhiliao'
    }
}

  在模版中訪問`username`。就是如下代碼`person.username`

4. 訪問字典的`key`時候也是使用`點.`來訪問,所以不能在字典中定義字典自己就有的屬性名看成`key`,不然字典的那個屬性將編程字典中的key了。

context = {
    'person': {
        'username':'zhiliao',
        'keys':'abc'
    }
}

  將`keys`做爲`person`這個字典的`key`了。所以之後在模版中訪問`person.keys`的時候,返回的不是這個字典的全部key,而是對應的值。

5.訪問列表或者元組,那麼也是經過`點.`的方式進行訪問,不能經過`中括號[]`的形式進行訪問。這一點和python中是不同的。示例代碼以下:

context = {
        'person': [ '張三','李四']
    }

{{ persons.1 }}

 

三 經常使用標籤

3-1 if 語句

1. 全部的標籤都是在`{%%}`之間。

2. if標籤有閉合標籤。就是`{% endif %}`。

3.if標籤的判斷運算符,就跟python中的判斷運算符是同樣的。`==、!=、<、<=、>、>=、in、not in、is、is not`這些均可以使用。

4. 還可使用`elif`以及`else`等標籤。

 

3-2 for...in...標籤

一、`for...in...`相似於`Python`中的`for...in...`。能夠遍歷列表、元組、字符串、字典等一切能夠遍歷的對象。示例代碼以下:

{% for person in persons %}
<p>{{ person.name }}</p>
{% endfor %}

二、若是想要反向遍歷,那麼在遍歷的時候就加上一個`reversed`。示例代碼以下:

{% for person in persons reversed %}
<p>{{ person.name }}</p>
{% endfor %}

三、遍歷字典的時候,須要使用`items`、`keys`和`values`等方法。在`DTL`中,執行一個方法不能使用圓括號的形式。遍歷字典示例代碼以下:

{% for key,value in person.items %}
<p>key:{{ key }}</p>
<p>value:{{ value }}</p>
{% endfor %}

四、在`for`循環中,`DTL`提供了一些變量可供使用。這些變量以下:

  • forloop.counter:當前循環的下標。以1做爲起始值。  
  • forloop.counter0:當前循環的下標。以0做爲起始值。  
  • forloop.revcounter:當前循環的反向下標值。好比列表有5個元素,那麼第一次遍歷這個屬性是等於5,第二次是4,以此類推。而且是以1做爲最後一個元素的下標。
  • forloop.revcounter0:相似於forloop.revcounter。不一樣的是最後一個元素的下標是從0開始。
  • forloop.first:是不是第一次遍歷。
  • forloop.last:是不是最後一次遍歷。
  • forloop.parentloop:若是有多個循環嵌套,那麼這個屬性表明的是上一級的for循環。

五、注意:模板中的for...in...沒有continue和break語句,這一點和Python中有很大的不一樣,必定要記清楚!

 

3-3 with標籤

1. 在模板中,想要定義變量,能夠經過`with`語句來實現。

2. `with`語句有兩種使用方式,第一種是`with xx=xxx`的形式,第二種是`with xxx as xxx`的形式。

3. 定義的變量只能在with語句塊中使用,在with語句塊外面使用取不到這個變量。

{% with zs=persons.0%}
    <p>{{ zs }}</p>
    <p>{{ zs }}</p>
{% endwith %}

下面這個由於超過了with語句塊,所以不能使用這個變量
<p>{{ zs }}</p>

{% with persons.0 as zs %}
    <p>{{ zs }}</p>
{% endwith %}

 

3-4 url 標籤

一、在模版中,咱們常常要寫一些`url`,好比某個`a`標籤中須要定義`href`屬性。固然若是經過硬編碼的方式直接將這個`url`寫死在裏面也是能夠的。可是這樣對於之後項目維護可能不是一件好事。所以建議使用這種反轉的方式來實現,相似於`django`中的`reverse`同樣。示例代碼以下:

<a href="{% url 'book:list' %}">圖書列表頁面</a>

二、若是`url`反轉的時候須要傳遞參數,那麼能夠在後面傳遞。可是參數分位置參數和關鍵字參數。位置參數和關鍵字參數不能同時使用。示例代碼以下:

# path部分
path('detail/<book_id>/',views.book_detail,name='detail')

# url反轉,使用位置參數
<a href="{% url 'book:detail' 1 %}">圖書詳情頁面</a>

# url反轉,使用關鍵字參數
<a href="{% url 'book:detail' book_id=1 %}">圖書詳情頁面</a>

三、若是想要在使用`url`標籤反轉的時候要傳遞查詢字符串的參數,那麼必需要手動在在後面添加。示例代碼以下:

<a href="{% url 'book:detail' book_id=1 %}?page=1">圖書詳情頁面</a>

四、若是須要傳遞多個參數,那麼經過空格的方式進行分隔。示例代碼以下:

<a href="{% url 'book:detail' book_id=1 page=2 %}">圖書詳情頁面</a>

 

3-5 autoescape 自動轉義標籤

1. DTL中默認已經開啓了自動轉義。會將那些特殊字符進行轉義。好比會將`<`轉義成`&lt;`等。

2. 若是你不知道本身在幹什麼,那麼最好是使用DTL的自動轉義。這樣網站纔不容易出現XSS漏洞

3. 若是變量確實是可信任的。那麼可使用`autoescape`標籤來關掉自動轉義。示例代碼以下:

{% autoescape off %}
    {{ info }}
{% endautoescape %}

 

3-6 verbatim標籤

  默認在`DTL`模板中是會去解析那些特殊字符的。好比`{%`和`%}`以及`{{`等。若是你在某個代碼片斷中不想使用`DTL`的解析引擎。那麼你能夠把這個代碼片斷放在`verbatim`標籤中。示例代碼下:

{% verbatim %}
{{if dying}}Still alive.{{/if}}
{% endverbatim %}

  

 四 經常使用過濾器

爲何須要過濾器?

  由於在DTL中,不支持函數的調用形式`()`,所以不能給函數傳遞參數,這將有很大的侷限性。而過濾器其實就是一個函數,能夠對須要處理的參數進行處理,而且還能夠額外接收一個參數(也就是說,最多隻能有2個參數)。

4-1 add過濾器

一、將傳進來的參數添加到原來的值上面。這個過濾器會嘗試將``和`參數`轉換成整型而後進行相加。若是轉換成整形過程當中失敗了,那麼會將`值`和`參數`進行拼接。若是是字符串,那麼會拼接成字符串,若是是列表,那麼會拼接成一個列表。示例代碼以下:

{{ value|add:"2" }}

  若是`value`是等於4,那麼結果將是6。若是`value`是等於一個普通的字符串,好比`abc`,那麼結果將是`abc2`。`add`過濾器的源代碼以下:

def add(value, arg):
"""Add the arg to the value."""
    try:
        return int(value) + int(arg)
    except (ValueError, TypeError):
        try:
            return value + arg
        except Exception:
            return ''

 

4-2 cut過濾器

一、移除值中全部指定的字符串。相似於`python`中的`replace(args,"")`。示例代碼以下:

{{ value|cut:" " }}

  以上示例將會移除`value`中全部的空格字符。`cut`過濾器的源代碼以下:

def cut(value, arg):
"""Remove all values of arg from the given string."""
    safe = isinstance(value, SafeData)
    value = value.replace(arg, '')
    if safe and arg != ';':
        return mark_safe(value)
    return value

 

4-3 date過濾器

一、將一個日期按照指定的格式,格式化成字符串。示例代碼以下:

# 數據
context = {
"birthday": datetime.now()
}

# 模版
{{ birthday|date:"Y/m/d" }}

二、那麼將會輸出`2018/02/01`。其中`Y`表明的是四位數字的年份,`m`表明的是兩位數字的月份,`d`表明的是兩位數字的日。 還有更多時間格式化的方式。見下表。

| 格式字符 | 描述 | 示例 |
| --- | --- | --- |
| Y | 四位數字的年份 | 2018 |
| m | 兩位數字的月份 | 01-12 |
| n | 月份,1-9前面沒有0前綴 | 1-12 |
| d | 兩位數字的天 | 01-31 |
| j | 天,可是1-9前面沒有0前綴 | 1-31 |
| g | 小時,12小時格式的,1-9前面沒有0前綴 | 1-12 |
| h | 小時,12小時格式的,1-9前面有0前綴 | 01-12 |
| G | 小時,24小時格式的,1-9前面沒有0前綴 | 1-23 |
| H | 小時,24小時格式的,1-9前面有0前綴 | 01-23 |
| i | 分鐘,1-9前面有0前綴 | 00-59 |
| s | 秒,1-9前面有0前綴 | 00-59 |

 

4-4 default 過濾器

一、若是值被評估爲`False`。好比`[]`,`""`,`None`,`{}`等這些在`if`判斷中爲`False`的值,都會使用`default`過濾器提供的默認值。示例代碼以下:

{{ value|default:"nothing" }}

  若是`value`是等於一個空的字符串。好比`""`,那麼以上代碼將會輸出`nothing`。

 

 

4-5 default_if_none過濾器

一、若是值是`None`,那麼將會使用`default_if_none`提供的默認值。這個和`default`有區別,`default`是全部被評估爲`False`的都會使用默認值。而`default_if_none`則只有這個值是等於`None`的時候纔會使用默認值。示例代碼以下:

{{ value|default_if_none:"nothing" }}

  若是`value`是等於`""`也即空字符串,那麼以上會輸出空字符串。若是`value`是一個`None`值,以上代碼纔會輸出`nothing`。

 

4-6 first 過濾器

一、返回列表/元組/字符串中的第一個元素。示例代碼以下:

{{ value|first }}

  若是`value`是等於`['a','b','c']`,那麼輸出將會是`a`。

 

4-7 last 過濾器

一、返回列表/元組/字符串中的最後一個元素。示例代碼以下:

{{ value|last }}

  若是`value`是等於`['a','b','c']`,那麼輸出將會是`c`。

 

4-8 floatformat 過濾器

一、使用四捨五入的方式格式化一個浮點類型。若是這個過濾器沒有傳遞任何參數。那麼只會在小數點後保留一個小數,若是小數後面全是0,那麼只會保留整數。固然也能夠傳遞一個參數,標識具體要保留幾個小數。

  • 沒有傳遞參數:
| value | 模版代碼 | 輸出 |
| --- | --- | --- |
| 34.23234 | `{{ value\|floatformat }}` | 34.2 |
| 34.000 | `{{ value\|floatformat }}` | 34 |
| 34.260 | `{{ value\|floatformat }}` | 34.3 |
  • 傳遞參數
| value | 模版代碼 | 輸出 |
| --- | --- | --- |
| 34.23234 | `{{value\|floatformat:3}}` | 34.232 |
| 34.0000 | `{{value\|floatformat:3}}` | 34.000 |
| 34.26000 | `{{value\|floatformat:3}}` | 34.260 |

 

4-9 join 過濾器 

一、相似與`Python`中的`join`,將列表/元組/字符串用指定的字符進行拼接。示例代碼以下:

{{ value|join:"/" }}

  若是`value`是等於`['a','b','c']`,那麼以上代碼將輸出`a/b/c`。

 

4-10 length 過濾器

一、獲取一個列表/元組/字符串/字典的長度。示例代碼以下:

{{ value|length }}

  若是`value`是等於`['a','b','c']`,那麼以上代碼將輸出`3`。若是`value`爲`None`,那麼以上將返回`0`。

 

4-11 lower 過濾器

一、將值中全部的字符所有轉換成小寫。示例代碼以下:

{{ value|lower }}

  若是`value`是等於`Hello World`。那麼以上代碼將輸出`hello world`。

 

4-12 upper 過濾器

一、相似於`lower`,只不過是將指定的字符串所有轉換成大寫

{{ value|upper}}

  若是`value`是等於`Hello World`。那麼以上代碼將輸出`hello world`。

 

4-13 random 過濾器

一、在被給的列表/字符串/元組中隨機的選擇一個值。示例代碼以下:

{{ value|random }}

  若是`value`是等於`['a','b','c']`,那麼以上代碼會在列表中隨機選擇一個。

 

4-14 safe 過濾器

一、標記一個字符串是安全的。也即會關掉這個字符串的自動轉義。示例代碼以下:

{{value|safe}}

  若是`value`是一個不包含任何特殊字符的字符串,好比`<a>`這種,那麼以上代碼就會把字符串正常的輸入。若是`value`是一串`html`代碼,那麼以上代碼將會把這個`html`代碼渲染到瀏覽器中。

 

4-15 slice 過濾器

一、相似於`Python`中的切片操做。示例代碼以下:

{{ some_list|slice:"2:" }}

  以上代碼將會給`some_list`從`2`開始作切片操做。

 

4-16 striptags 過濾器

一、刪除字符串中全部的`html`標籤。示例代碼以下:

{{ value|striptags }}

  若是`value`是`<strong>hello world</strong>`,那麼以上代碼將會輸出`hello world`。

 

4-17 truncatechars 過濾器

一、給定的字符串長度超過了過濾器指定的長度。那麼就會進行切割,而且會拼接三個點來做爲省略號。示例代碼以下:

{{ value|truncatechars:5 }}

  若是`value`是等於`北京歡迎您~`,那麼輸出的結果是`北京...`。可能你會想,爲何不會`北京歡迎您...`呢。由於三個點也佔了三個字符,因此`北京`+三個點的字符長度就是5。

 

4-18 truncatechars_html 過濾器

一、相似於`truncatechars`,只不過是不會切割`html`標籤。示例代碼以下:

{{ value|truncatechars:5 }}

  若是`value`是等於`<p>北京歡迎您~</p>`,那麼輸出將是`<p>北京...</p>`。

 

 五 自定義過濾器

一、首先在某個app中,建立一個python包,叫作`templatetags`,注意,這個包的名字必須爲`templatetags`,否則就找不到。

二、在這個`templatetags`包下面,建立一個python文件用來存儲過濾器。

三、在新建的python文件中,定義過濾器(也就是函數),這個函數的第一個參數永遠是被過濾的那個值,而且若是在使用過濾器的時候傳遞參數,那麼還能夠定義另一個參數。可是過濾器最多隻能有2個參數

四、在寫完過濾器(函數)後,要使用`django.template.Library.filter`進行註冊

五、還要把這個過濾器所在的這個app添加到`settings==>INSTALLED_APS`中,進行安裝,否則Django也找不到這個過濾器。

六、在模板中使用`load`標籤加載過濾器所在的python包。

七、可使用過濾器了。

八、`django.template.Library.filter`還能夠看成裝飾器來使用。若是`filter`函數沒有傳遞任何參數,那麼將會使用這個函數的名字來做爲過濾器的名字。固然若是你不想使用函數的名字來做爲過濾器的名字,也能夠傳遞一個`name`參數。示例代碼以下:

@register.filter('my_greet')
    def greet(value,word):
        return value + word

 

六 模板結構

6-1 include 標籤

一、有些模版代碼是重複的。所以能夠單獨抽取出來,之後哪裏須要用到,就直接使用`include`進來就能夠了。

二、若是想要在`include`子模版的時候,傳遞一些參數,那麼可使用`with xxx=xxx`的形式。示例代碼以下:

{% include 'header.html' with username='zhiliao' %}

 

6-2 模板繼承

一、在前端頁面開發中。有些代碼是須要重複使用的。這種狀況可使用`include`標籤來實現。也可使用另一個比較強大的方式來實現,那就是模版繼承。模版繼承相似於`Python`中的類,在父類中能夠先定義好一些變量和方法,而後在子類中實現。模版繼承也能夠在父模版中先定義好一些子模版須要用到的代碼,而後子模版直接繼承就能夠了。而且由於子模版確定有本身的不一樣代碼,所以能夠在父模版中定義一個block接口,而後子模版再去實現。如下是父模版的代碼:

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="{% static 'style.css' %}" />
<title>{% block title %}個人站點{% endblock %}</title>
</head>

<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">首頁</a></li>
<li><a href="/blog/">博客</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>

   這個模版,咱們取名叫作`base.html`,定義好一個簡單的`html`骨架,而後定義好兩個`block`接口,讓子模版來根據具體需求來實現。子模板而後經過`extends`標籤來實現,示例代碼以下:

{% extends "base.html" %}
{% block title %}博客列表{% endblock %}
{% block content %}
{% for entry in blog_entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

注意:extends標籤必須放在模版的第開始的位置;子模板中的代碼必須放在block中,不然將不會被渲染

二、若是在某個`block`中須要使用父模版的內容,那麼可使用`{{block.super}}`來繼承。好比上例,`{%block title%}`,若是想要使用父模版的`title`,那麼能夠在子模版的`title block`中使用`{{ block.super }}`來實現。

三、在定義`block`的時候,除了在`block`開始的地方定義這個`block`的名字,還能夠在`block`結束的時候定義名字。好比`{% block title %}{% endblock title %}`。這在大型模版中顯得尤爲有用,能讓你快速的看到`block`包含在哪裏。

 

七 加載靜態文件

  在一個網頁中,不只僅只有一個`html`骨架,還須要`css`樣式文件`js`執行文件以及一些圖片等。所以在`DTL`中加載靜態文件是一個必需要解決的問題。在`DTL`中,使用`static`標籤來加載靜態文件。要使用`static`標籤,首先須要`{% load static %}`。加載靜態文件的步驟以下:

1)首先確保`django.contrib.staticfiles`已經添加到`settings.INSTALLED_APPS`中。

2)確保在`settings.py`中設置了`STATIC_URL`。

3)在已經安裝了的`app`下建立一個文件夾叫作`static`,而後再在這個`static`文件夾下建立一個當前`app`的名字的文件夾,再把靜態文件放到這個文件夾下。例如你的`app`叫作`book`,有一個靜態文件叫作`zhiliao.jpg`,那麼路徑爲`book/static/book/zhiliao.jpg`。(爲何在`app`下建立一個`static`文件夾,還須要在這個`static`下建立一個同`app`名字的文件夾呢?緣由是若是直接把靜態文件放在`static`文件夾下,那麼在模版加載靜態文件的時候就是使用`zhiliao.jpg`,若是在多個`app`之間有同名的靜態文件,這時候可能就會產生混淆。而在`static`文件夾下加了一個同名`app`文件夾,在模版中加載的時候就是使用`app/zhiliao.jpg`,這樣就能夠避免產生混淆。)

4)若是有一些靜態文件是不和任何`app`掛鉤的。那麼能夠在`settings.py`中添加`STATICFILES_DIRS`,之後`DTL`就會在這個列表的路徑中查找靜態文件。好比能夠設置爲:

STATICFILES_DIRS = [
    os.path.join(BASE_DIR,"static")
]

5)在模版中使用`load`標籤加載`static`標籤。好比要加載在項目的`static`文件夾下的`style.css`的文件。那麼示例代碼以下:

{% load static %}
<link rel="stylesheet" href="{% static 'style.css' %}">

6)若是不想每次在模版中加載靜態文件都使用`load`加載`static`標籤,那麼能夠在`settings.py`中的`TEMPLATES/OPTIONS`添加`'builtins':['django.templatetags.static']`,這樣之後在模版中就能夠直接使用`static`標籤,而不用手動的`load`了。

7) 若是沒有在`settings.INSTALLED_APPS`中添加`django.contrib.staticfiles`。那麼咱們就須要手動的將請求靜態文件的`url`與靜態文件的路徑進行映射了。示例代碼以下:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
# 其餘的url映射
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
相關文章
相關標籤/搜索