模板渲染的官方文檔html
關於模板渲染你只須要記兩種特殊符號(語法):前端
{{ }}和 {% %}數據庫
變量相關的用{{}},邏輯相關的用{%%}。django
在Django的模板語言中按此語法使用:{{ 變量名 }}。後端
當模版引擎遇到一個變量,它將計算這個變量,而後用結果替換掉它自己。 變量的命名包括任何字母數字以及下劃線 ("_")的組合。 變量名稱中不能有空格或標點符號。瀏覽器
深度查詢據點符(.)在模板語言中有特殊的含義。當模版系統遇到點("."),它將以這樣的順序查詢:緩存
字典查詢(Dictionary lookup):即字典經過 字典名.鍵名 來調用該鍵對應的值.
屬性或方法查詢(Attribute or method lookup):自定義類對象經過 對象名.方法名 或對象名.屬性名 來調用相應的方法或屬性,注意調用方法不加括號,因此只能調用不傳參的簡單方法.
數字索引查詢(Numeric index lookup):列表取值經過 列表名.索引 來取對應的值.安全
栗子:app
def index(request): import datetime s = "hello" l = [111, 222, 333] # 列表 dic = {"name": "yuan", "age": 18} # 字典 date = datetime.date(1993, 5, 2) # 日期對象 class Person(object): def __init__(self, name): self.name = name def dream(self): return 'dreamer' person_yuan = Person("chao") # 自定義類對象 person_egon = Person("yantao") person_alex = Person("jinxin") person_list = [person_yuan, person_egon, person_alex] return render(request, "index.html", {"l": l, "dic": dic, "date": date, "person_list": person_list}) # return render(request,'index.html',locals()) #locals()獲取函數內容全部的變量,轉換成字典的鍵值對,而後經過render方法給了index.html文件進行模板渲染,若是你圖省事,你能夠用它,可是不少多餘的變量也被傳進去了,效率低
<h4>{{s}}</h4> <h4>列表:{{ l.0 }}</h4> # 0是列表的索引 <h4>列表:{{ l.2 }}</h4> <h4>字典:{{ dic.name }}</h4> # 列表.鍵名,不加引號 <h4>日期:{{ date.year }}</h4> <!--取列表的第1個對象的name屬性的值--> <h4>類對象列表:{{ person_list.0.name }}</h4> <!--取列表的第1個對象的dream方法的返回值,若是沒有返回值,拿到的是None--> <h4>類對象列表:{{ person_list.0.dream }}</h4> 注意: 調用對象裏面的方法的時候,不須要寫括號來執行,而且只能執行不須要傳參數的方法,若是你的這個方法須要傳參數,那麼模板語言不支持,不能幫你渲染
在Django的模板語言中(因此是使用在HTML文件中的),經過使用 過濾器 來改變變量的顯示。xss
過濾器的語法: {{ value|filter_name:參數 }}
使用管道符"|"來應用過濾器。
例如:{{ name|lower }}會將name變量應用lower過濾器以後再顯示它的值。lower在這裏的做用是將文本全都變成小寫。
注意事項:
若是一個變量是false或者爲空,使用給定的默認值。 不然,使用變量的值。
{{ value|default:"nothing"}}
若是value沒有傳值或者值爲空的話就顯示nothing
返回值的長度,做用於字符串和列表。
{{ value|length }}
返回value的長度,如 value=['a', 'b', 'c', 'd']的話,就顯示4.
將值格式化爲一個 「人類可讀的」 文件尺寸 (例如 '13 KB'
, '4.1 MB'
, '102 bytes'
, 等等)。例如:
{{ value|filesizeformat }}
若是 value 是 123456789,輸出將會是 117.7 MB。
切片,若是 value="hello world",還有其餘可切片的數據類型
{{value|slice:"2:-1"}}
格式化,若是 value=datetime.datetime.now()
{{ value|date:"Y-m-d H:i:s"}}
關於時間日期的可用的參數(除了Y,m,d等等)還有不少,有興趣的能夠去查查看看。
Django的模板中在進行模板渲染的時候會對HTML標籤和JS等語法標籤進行自動轉義,緣由顯而易見,這樣是爲了安全,django擔憂這是用戶添加的數據,好比若是有人給你評論的時候寫了一段js代碼,這個評論一提交,js代碼就執行啦,這樣你是否是能夠搞一些壞事兒了,寫個彈窗的死循環,那瀏覽器還能用嗎,是否是會一直彈窗啊,這叫作xss攻擊,因此瀏覽器不讓你這麼搞,給你轉義了。可是有的時候咱們可能不但願這些HTML元素被轉義,好比咱們作一個內容管理系統,後臺添加的文章中是通過修飾的,這些修飾多是經過一個相似於FCKeditor編輯加註了HTML修飾符的文本,若是自動轉義的話顯示的就是保護HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,若是是一個單獨的變量咱們能夠經過過濾器「|safe」的方式告訴Django這段代碼是安全的沒必要轉義。
咱們去network那個地方看看,瀏覽器看到的都是渲染以後的結果,經過network的response的那個部分能夠看到,這個a標籤所有是特殊符號包裹起來的,並非一個標籤,這都是django搞得事情。
好比:
value = "<a href='#'>點我</a>" 和 value="<script>alert('123')</script>"
{{ value|safe}}
不少網站,都會對你提交的內容進行過濾,一些敏感詞彙、特殊字符、標籤、黃賭毒詞彙等等,你一提交內容,人家就會檢測你提交的內容,若是包含這些詞彙,就不讓你提交,其實這也是解決xss攻擊的根本途徑,例如博客園:
若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾。
參數:截斷的字符數
{{ value|truncatechars:9}} #注意:最後那三個省略號也是9個字符裏面的,也就是這個9截斷出來的是6個字符+3個省略號,有人會說,怎麼展開啊,配合前端的點擊事件就行啦
在必定數量的字後截斷字符串,是截多少個單詞。
例如:‘hello girl hi baby yue ma’,
{{ value|truncatewords:3}} #上面例子獲得的結果是 'hello girl h1...'
移除value中全部的與給出的變量相同的字符串
{{ value|cut:' ' }}
若是value爲'i love you',那麼將輸出'iloveyou'.
使用字符串鏈接列表,{{ list|join:', ' }},就像Python的str.join(list)
將日期格式設爲自該日期起的時間(例如,「4天,6小時」)。
採用一個可選參數,它是一個包含用做比較點的日期的變量(不帶參數,比較點爲如今)。 例如,若是blog_date是表示2006年6月1日午夜的日期實例,而且comment_date是2006年6月1日08:00的日期實例,則如下將返回「8小時」:
{{ blog_date|timesince:comment_date }}
分鐘是所使用的最小單位,對於相對於比較點的將來的任何日期,將返回「0分鐘」。
似於timesince,除了它測量從如今開始直到給定日期或日期時間的時間。 例如,若是今天是2006年6月1日,而conference_date是保留2006年6月29日的日期實例,則{{ conference_date | timeuntil }}將返回「4周」。
使用可選參數,它是一個包含用做比較點的日期(而不是如今)的變量。 若是from_date包含2006年6月22日,則如下內容將返回「1周」:
{{ conference_date|timeuntil:from_date }}
標籤看起來像是這樣的: {% tag %}
。標籤比變量更加複雜:一些在輸出中建立文本,一些經過循環或邏輯來控制流程,一些加載其後的變量將使用到的額外信息到模版中。一些標籤須要開始和結束標籤 (例如{% tag %} ...
標籤 內容 ... {% endtag %})。
遍歷每個元素: 寫個for,而後 tab鍵自動生成for循環的結構,循環很基礎,就這麼簡單的用,沒有什麼break之類的,複雜一些的功能,你要經過js
{% for person in person_list %} <p>{{ person.name }}</p> <!--凡是變量都要用兩個大括號括起來--> {% endfor %}
能夠利用{% for obj in list reversed %}反向完成循環。
遍歷一個字典:
{% for key,val in dic.items %} <p>{{ key }}:{{ val }}</p> {% endfor %}
注:循環序號能夠經過{{forloop}}顯示,必須在循環內部用
forloop.counter 當前循環的索引值(從1開始),forloop是循環器,經過點來使用功能 forloop.counter0 當前循環的索引值(從0開始) forloop.revcounter 當前循環的倒序索引值(從1開始)(只是將索引倒敘,值仍是正序的) forloop.revcounter0 當前循環的倒序索引值(從0開始) forloop.first 當前循環是否是第一次循環(布爾值) forloop.last 當前循環是否是最後一次循環(布爾值) forloop.parentloop 本層循環的外層循環的對象(寫在內層循環中,至關於寫在外層循環中的forloop),再經過上面的幾個屬性來顯示外層循環的計數等
(若是要在內層循環中顯示外層循環的執行次數,要使用forloop.parentloop.counter)
for 標籤帶有一個可選的{% empty %} 從句,以便在給出的組是空的或者沒有被找到時,能夠有所操做。
{% for person in person_list %} <p>{{ person.name }}</p> {% empty %} <p>sorry,no person here</p> {% endfor %}
{% if %}會對一個變量求值,若是它的值是「True」(存在、不爲空、且不是boolean類型的false值),對應的內容塊會輸出。
{% if num > 100 or num < 0 %} <p>無效</p> <!--不知足條件,不會生成這個標籤--> {% elif num > 80 and num < 100 %} <p>優秀</p> {% else %} <!--也是在if標籤結構裏面的--> <p>湊活吧</p> {% endif %}
固然也能夠只有if和else
{% if user_list|length > 5 %} <!--結合過濾器來使用--> 七座豪華SUV {% else %} 黃包車 {% endif %}
if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷,注意條件兩邊都有空格。
使用一個簡單地名字緩存一個複雜的變量,多用於給一個複雜的變量起別名,當你須要使用一個「昂貴的」方法(好比訪問數據庫)不少次的時候是很是有用的
例如:
注意等號左右不要加空格。
{% with total=business.employees.count %} {{ total }} <!--只能在with語句體內用--> {% endwith %}
或
{% with business.employees.count as total %} {{ total }} {% endwith %}
咱們以post方式提交表單的時候,會報錯,還記得咱們在settings裏面的中間件配置裏面把一個csrf的防護機制給註銷了啊,自己不該該註銷的,而是應該學會怎麼使用它,而且不讓本身的操做被forbiden,經過這個東西就能搞定。
這個標籤用於跨站請求僞造保護,
在頁面的form表單裏面(注意是在form表單裏面)任何位置寫上{% csrf_token %},這個東西模板渲染的時候替換成了<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">,隱藏的,這個標籤的值是個隨機字符串,提交的時候,這個東西也被提交了,首先這個東西是咱們後端渲染的時候給頁面加上的,那麼當你經過我給你的form表單提交數據的時候,你帶着這個內容我就認識你,不帶着,我就禁止你,由於後臺咱們django也存着這個東西,和你這個值相同的一個值,能夠作對應驗證是否是我給你的token,存儲這個值的東西咱們後面再學,你先知道一下就好了,就像一個咱們後臺給這個用戶的一個通行證,若是你用戶沒有按照我給你的這個正常的頁面來post提交表單數據,或者說你沒有先去請求我這個登錄頁面,而是直接模擬請求來提交數據,那麼我就能知道,你這個請求是非法的.
爬蟲發送post請求簡單模擬:
import requests res = requests.post('http://127.0.0.1:8000/login/',data={ 'username':'chao', 'password':'123' }) print(res.text)
{# ... #}
1. Django的模板語言不支持連續判斷,即不支持如下寫法:
{% if a > b > c %} ... {% endif %}
2. Django的模板語言中屬性的優先級大於方法(瞭解)
def xx(request): d = {"a": 1, "b": 2, "c": 3, "items": "100"} return render(request, "xx.html", {"data": d})
如上,咱們在使用render方法渲染一個頁面的時候,傳的字典d有一個key是items而且還有默認的 d.items() 方法,此時在模板語言中:
{{ data.items }}
默認會取d的items key的值(即會取上面自定義的字典d的鍵item對應的值100)。
Django模版引擎中最強大也是最複雜的部分就是模版繼承了。模版繼承可讓您建立一個基本的「骨架」模版,它包含您站點中的所有元素,而且能夠定義可以被子模版覆蓋的 blocks 。
經過從下面這個例子開始,能夠容易的理解模版繼承:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! --> <title> {% block title %} 母板的title信息 {% endblock %} </title> <style> body{ padding: 0; margin: 0; } .nav{ background-color: red; height: 40px; } .left_list div{ width: 100px; height: 20px; background-color: pink; border-bottom:1px solid black ; } .left_list{ float: left; width: 100px; } .content{ float: right; width: 600px; height: 100px; } </style> </head> <body> <div class="nav"> <a href="">新聞</a> <a href="">問也</a> <a href="">圖片</a> </div> <div class="left_list"> {% block list %} <div><a href="/index/">首頁</a></div> <div><a href="/order/">訂單頁</a></div> <div><a href="/user/">我的中心</a></div> {% endblock %} </div> <div class="content"> {% block content %} 母板預留的地方 {% endblock %} </div> </body> </html>
{% extends 'base.html' %} {% block title %} {# 首頁#} {% endblock %} {% block content %} <a href="">首頁</a> <span>首頁介紹</span> {{ block.super }} {% endblock %}
extends
標籤是這裏的關鍵。它告訴模版引擎,這個模版「繼承」了另外一個模版。當模版系統處理這個模版時,首先,它將定位父模版——在此例中,就是「base.html」。
那時,模版引擎將注意到 base.html
中的兩個 block
標籤,並用子模版中的內容來替換這些block。
請注意,若是子模版沒有定義 父模板中的block,系統就會使用父模版中的值。父模版的 {% block %}
標籤中的內容老是被用做備選內容(fallback)。
這種方式使代碼獲得最大程度的複用,而且使得添加內容到共享的內容區域更加簡單,例如,部分範圍內的導航。
這裏是使用繼承的一些提示:
若是你在模版中使用 {% extends %}
標籤,它必須是模版中的第一個標籤。其餘的任何狀況下,模版繼承都將沒法工做,模板渲染的時候django都不知道你在幹啥。(只有一個父模板,不能同時多繼承多個模板)
在base模版中設置越多的 {% block %}
標籤越好。請記住,子模版沒必要定義所有父模版中的blocks,因此,你能夠在大多數blocks中填充合理的默認內容,而後,只定義你須要的那一個。多一點鉤子總比少一點好。
若是你發現你本身在大量的模版中複製內容,那可能意味着你應該把內容移動到父模版中的一個 {% block %}
中。
If you need to get the content of the block from the parent template, the {{ block.super }}
variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using {{ block.super }}
will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template. 將子頁面的內容和繼承的母版中block裏面的內容同時保留,使用{{ block.super }}保留父模板中的內容,同時寫本身想要添加的標籤,好比下面的寫法:
{% block content %} <a href="">首頁</a> <span>首頁介紹</span> {{ block.super }} {% endblock %}
爲了更好的可讀性,你也能夠給你的 {% endblock %}
標籤一個 名字 。例如:
{% block content %} ... {% endblock content %}
在大型模版中,這個方法幫你清楚的看到哪個 {% block %}
標籤被關閉了。
block
標籤。
六 組件
能夠將經常使用的頁面內容如導航條,頁尾信息等組件保存在單獨的文件中,而後在須要使用的地方,文件的任意位置按以下語法導入便可。
{% include 'navbar.html' %}
例如:有個以下的導航欄,nav.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .c1{ background-color: red; height: 40px; } </style> </head> <body> <div class="c1"> <div> <a href="">xx</a> <a href="">dd</a> </div> </div> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% include 'nav.html' %} <h1>xxxxxxxxxx</h1> </body> </html>
這些咱們後面用到的時候再講:
一、在settings中的INSTALLED_APPS配置當前app,否則django沒法找到自定義的simple_tag.
二、在app中建立templatetags模塊(模塊名只能是templatetags)
三、建立任意 .py 文件,如:my_tags.py
from django import template from django.utils.safestring import mark_safe register = template.Library() #register的名字是固定的,不可改變 @register.filter def filter_multi(v1,v2): return v1 * v2 <br> @register.simple_tag #和自定義filter相似,只不過接收更靈活的參數,沒有個數限制。 def simple_tag_multi(v1,v2): return v1 * v2 <br> @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,) return mark_safe(result)
四、在使用自定義simple_tag和filter的html文件中導入以前建立的 my_tags.py
{% load my_tags %}
五、使用simple_tag和filter(如何調用)
-------------------------------.html
{% load xxx %}
# num=12
{{ num|filter_multi:2 }} #24
{{ num|filter_multi:"[22,333,4444]" }}
{% simple_tag_multi 2 5 %} 參數不限,但不能放在if for語句中
{% simple_tag_multi num 5 %}
注意:filter能夠用在if等語句後,simple_tag不能夠
{% if num|filter_multi:30 > 100 %} {{ num|filter_multi:30 }} {% endif %}
多用於返回html代碼片斷
示例:
templatetags/my_inclusion.py
from django import template register = template.Library() @register.inclusion_tag('result.html') def show_results(n): n = 1 if n < 1 else int(n) data = ["第{}項".format(i) for i in range(1, n+1)] return {"data": data}
templates/snippets/result.html
<ul> {% for choice in data %} <li>{{ choice }}</li> {% endfor %} </ul>
templates/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>inclusion_tag test</title> </head> <body> {% load inclusion_tag_test %} {% show_results 10 %} </body> </html>
{% load static %} <img src="{% static "images/hi.jpg" %}" alt="Hi!" />
引用JS文件時使用:
{% load static %} <script src="{% static "mytest.js" %}"></script>
某個文件多處被用到能夠存爲一個變量
{% load static %} {% static "images/hi.jpg" as myphoto %} <img src="{{ myphoto }}"></img>
{% load static %} <img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" />
或者
{% load static %} {% get_static_prefix as STATIC_PREFIX %} <img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" /> <img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />