目標 css
- 模板介紹
- 模板變量
- 經常使用標籤
- 經常使用過濾器
- 自定義過濾器
- 模板結構
- 加載靜態文件
一 模板介紹
在以前的章節中,視圖函數只是直接返回文本,而在實際生產環境中其實不多這樣用,由於實際的頁面大可能是帶有樣式的HTML代碼,這可讓瀏覽器渲染出很是漂亮的頁面。目前市面上有很是多的模板系統,其中最知名最好用的就是DTL和Jinja2。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中默認已經開啓了自動轉義。會將那些特殊字符進行轉義。好比會將`<`轉義成`<`等。
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)