一、Django的路由層php
URL配置(URLconf)就像Django所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函數之間的映射表;咱們就是以這種方式告訴Django,對於客戶端發來的某個URL該調用哪一段邏輯代碼對應執行。css
(1)、簡單的路由配置html
from django.contrib import admin from django.urls import path, re_path from blog import views urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^$', views.index), # 含有正則匹配根路徑 path('shopping', views.shopping), # 不含正則使用path re_path(r'^active/(\d{4})/$', views.active), # 正則也可使用分組 ,匹配任意四位數字 如 active/1234/ ]
解釋:urlpatterns列表中是訪問路徑和視圖函數的映射關係。python
注意:程序員
^articles
而不是 ^/articles
。(2)有名分組ajax
上面的示例使用簡單的、沒有命名的正則表達式組(經過圓括號)來捕獲URL 中的值並以位置 參數傳遞給視圖。在更高級的用法中,可使用命名的正則表達式組來捕獲URL 中的值並以關鍵字 參數傳遞給視圖。正則表達式
在python 正則表達式中, 命名正則表達式組的語法是(?P<name>正則表達式), 其中 name 是組的名字 , 正則表達式 是要匹配的內容。數據庫
from django.contrib import admin from django.urls import path, re_path from blog import views urlpatterns = [ re_path(r'^articles/2003/$', views.special_case_2003), re_path(r'^articles/(?P<year>\d{4})/$', views.year_archive), re_path(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive), re_path(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', views.article_detail), path('admin/', admin.site.urls), 】
這個實現與前面的示例徹底相同,只有一個細微的差異:捕獲的值做爲關鍵字參數而不是位置參數傳遞給視圖函數。django
在實際應用中,這意味你的URLconf 會更加明晰且不容易產生參數順序問題的錯誤 —— 你能夠在你的視圖函數定義中從新安排參數的順序。固然,這些好處是以簡潔爲代價。瀏覽器
(3)path轉換器
from django.contrib import admin from django.urls import path, re_path from blog import views urlpatterns = [ path('articles/2018/', views.special_case_2018), path('articles/<int:year>/', views.year_archive), path('articles/<int:year>/<int:month>/', views.month_archive), path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail), ]
默認狀況下,Django內置下面的路徑轉換器:
(4)、分發
咱們發現,Django生成的項目中只有一個全局的urls.py文件,這就意味着咱們須要把全部應用的訪問路徑與視圖函數的映射關係都放到這一個urls.py文件中,但應用較多時會發現這樣作不太好,因而咱們但願每一個應用各自的映射關係可以放到本身的應用目錄中。這是咱們就要用到分發的功能,也就是在每一個app裏,各自建立一個urls.py
路由模塊,而後從根路由出發,將app所屬的url請求,所有轉發到相應的urls.py
模塊中。
項目的urls.py文件:
from django.contrib import admin from django.urls import path, re_path, include urlpatterns = [ re_path(r'^admin/', admin.site.urls), re_path(r'^blog/', include('blog.urls')), ]
blog的urls.py文件:
from django.urls import re_path from blog import views urlpatterns = [ re_path(r'^articles/(\d{4})/$', views.article_year), re_path(r'^articles/2003/$', views.special_year), re_path(r'^articles/(\d{4})/(\d{2})/$', views.article_month), re_path(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', views.article_day), ]
(5)、反向解析
在使用Django 項目時,一個常見的需求是得到URL的最終形式,以用於嵌入到生成的內容中(視圖中和顯示給用戶的URL等)或者用於處理服務器端的導航(重定向等)。人們強烈但願不要硬編碼這些URL(費力、不可擴展且容易產生錯誤)或者設計一種與URLconf 絕不相關的專門的URL 生成機制,由於這樣容易致使必定程度上產生過時的URL(簡而言之,代碼中的URL寫死就容易出現問題)。
在須要URL 的地方,對於不一樣層級,Django 提供不一樣的工具用於URL 反查:
1)在模板中的url:使用url 模板標籤{% url "別名" 動態變量名 %}。
2)在Python 代碼中:使用from django.urls import reverse函數。
urls.py文件
from django.urls import re_path from blog import views urlpatterns = [ re_path(r'^articles/([0-9]{4})/$', views.year_archive, name='year-archive'), # 給這個路徑起了一個別名year-archive, 注意url匹配中有正則,也就是說url中有動態參數,因此url模板標籤有要有動態變量接收 ]
在模板中(此示例是url含動態變量的狀況,不含動態變量則不寫動態變量名便可):
<a href="{% url 'year-archive' 2012 %}">2012 Archive</a> 若上面別名爲year-archive的url是:http://www.baidu.com/articles/2008/ 則這個a標籤連接爲:http://www.baidu.com/articles/2008/2012 <ul> {% for yearvar in year_list %} <li><a href="{% url 'year-archive' yearvar %}">{{ yearvar }} Archive</a></li> {% endfor %} </ul>
在python代碼(視圖函數中,此示例url中含動態變量,沒有動態變量則不寫args=()便可):
from django.urls import reverse from django.http import HttpResponseRedirect def redirect_to_year(request): year = 2006 return HttpResponseRedirect( reverse('year-archive', args=(year,))) # 同redirect("/path/"), args=(year,)接收url中動態變量
注意:當命名你的URL 模式時,請確保使用的名稱不會與其它應用中名稱衝突。若是你的URL 模式叫作comment,而另一個應用中也有一個一樣的名稱,當你在模板中使用這個名稱的時候不能保證將插入哪一個URL。在URL 名稱中加上一個前綴,好比應用的名稱,將減小衝突的可能。咱們建議使用myapp-comment 而不是comment
(6)、命名空間
命名空間(英語:Namespace)是表示標識符的可見範圍。一個標識符可在多個命名空間中定義,它在不一樣命名空間中的含義是互不相干的。這樣,在一個新的命名空間中可定義任何標識符,它們不會與任何已有的標識符發生衝突,由於已有的定義都處於其它命名空間中。
上面反向解析中,因爲name沒有做用域,Django在反解URL時,會在項目全局順序搜索,當查找到第一個name指定URL時,當即返回。咱們在開發項目時,會常用name屬性反解出URL,當不當心在不一樣的app的urls中定義相同的name時,可能會致使URL反解錯誤,爲了不這種事情發生,引入了命名空間。以下示例:
項目下urls.py文件:
urlpatterns = [
url(r'^admin/', admin.site.urls), url(r'^app01/', include("app01.urls", namespace="app01")), url(r'^app02/', include("app02.urls", namespace="app02")), ]
app01下的urls.py:
urlpatterns = [
url(r'^index/', index, name="index"), ]
app02下的urls.py:
urlpatterns = [
url(r'^index/', index, name="index"), ]
app01下的views.py:
from django.core.urlresolvers import reverse def index(request): return HttpResponse(reverse("app01:index"))
app02下的views.py:
from django.core.urlresolvers import reverse def index(request): return HttpResponse(reverse("app02:index"))
二、Django的視圖層
(1)、視圖函數
一個視圖函數,簡稱視圖,是一個簡單的Python函數,它接受Web請求而且返回Web響應。響應能夠是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片. . . ,是任何東西均可以。不管視圖自己包含什麼邏輯,都要返回響應。代碼寫在哪裏也無所謂,只要它在你的Python目錄下面。除此以外沒有更多的要求了——能夠說「沒有什麼神奇的地方」。爲了將代碼放在某處,約定是將視圖放置在項目或應用程序目錄中的名爲views.py的文件中。
下面是一個返回包含當前日期和時間的HTML文檔的視圖:
from django.shortcuts import render, HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now # 這裏html頁面代碼有刪減,不該該這麼寫,爲了便於理解這樣表示 return HttpResponse(html)
分析上面的代碼:
首先,咱們從django.shortcuts模塊導入了HttpResponse類,以及python的datetime庫。
接着,咱們定義了current_datetime函數,它就是視圖函數。每一個視圖函數都使用HttpRequest對象做爲第一個參數,而且一般稱之爲request。
注意,視圖函數的名稱並不重要;不須要用一個統一的命名方式來命名,以便讓Django識別它。咱們將其命名爲current_datetime,是由於這個名稱可以精確地反映出它的功能。
這個視圖會返回一個HttpResponse對象,其中包含生成的響應。每一個視圖函數都負責返回一個HttpResponse對象。
總結:視圖層,熟練掌握兩個對象便可:請求對象(request)和響應對象(HttpResponse)。
(2)、HttpRequest對象
a、request屬性
django將請求報文中的請求首行、頭部信息、內容主體封裝成 HttpRequest 類中的屬性。 除了特殊說明的以外,其餘均爲只讀的。
①、HttpRequest.GET 一個相似於字典的對象,包含 HTTP GET的全部參數。詳情請參考 QueryDict 對象。 ②、HttpRequest.POST 一個相似於字典的對象,若是請求中包含表單數據,則將這些數據封裝成 QueryDict 對象。 POST 請求能夠帶有空的POST字典 — 若是經過HTTP POST方法發送一個表單,可是表單中沒有任何的數據,QueryDict 對象依然會被建立。 所以,不該該使用if request.POST來檢查使用的是不是POST 方法;而應該使用 if request.method == "POST"。 另外:若是使用 POST 上傳文件的話,文件信息將包含在 FILES 屬性中。 注意:鍵值對的值是多個的時候,好比checkbox類型的input標籤,或者select標籤,須要用:request.POST.getlist("hobby")。 ③、HttpRequest.body 一個字符串,表明請求報文的主體。在處理非 HTTP 形式的報文時很是有用,例如:二進制圖片、XML,Json等。 可是,若是要處理表單數據的時候,推薦仍是使用 HttpRequest.POST。 ④、HttpRequest.path 一個字符串,表示請求的路徑(不含域名和參數),例如:"/music/bands/the_beatles/"。 ⑤、HttpRequest.method 一個字符串,表示請求使用的HTTP 方法,比較時必須使用大寫,例如:"GET"、"POST"。 ⑥、HttpRequest.encoding 一個字符串,表示提交的數據的編碼方式(若是爲 None 則表示使用DEFAULT_CHARSET 的設置,默認爲 'utf-8')。 這個屬性是可寫的,你能夠經過修改它來修改訪問表單數據使用的編碼。 接下來對屬性的任何訪問(例如從GET或POST中讀取數據)將使用新的 encoding 值。若是你知道表單數據的編碼不是DEFAULT_CHARSET,則使用它。 ⑦、HttpRequest.META 一個標準的Python 字典,包含全部的HTTP 首部。具體的頭部信息取決於客戶端和服務器,下面是一些示例: CONTENT_LENGTH —— 請求的正文的長度(是一個字符串)。 CONTENT_TYPE —— 請求的正文的MIME 類型。 HTTP_ACCEPT —— 響應可接收的Content-Type。 HTTP_ACCEPT_ENCODING —— 響應可接收的編碼。 HTTP_ACCEPT_LANGUAGE —— 響應可接收的語言。 HTTP_HOST —— 客服端發送的HTTP Host 頭部。 HTTP_REFERER —— Referring 頁面。 HTTP_USER_AGENT —— 客戶端的user-agent 字符串。 QUERY_STRING —— 單個字符串形式的查詢字符串(未解析過的形式)。 REMOTE_ADDR —— 客戶端的IP 地址。 REMOTE_HOST —— 客戶端的主機名。 REMOTE_USER —— 服務器認證後的用戶。 REQUEST_METHOD —— 一個字符串,例如"GET" 或"POST"。 SERVER_NAME —— 服務器的主機名。 SERVER_PORT —— 服務器的端口(是一個字符串)。 從上面能夠看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 以外,請求中的任何 HTTP 首部轉換爲 META 的鍵時, 都會將全部字母大寫並將鏈接符替換爲下劃線最後加上 HTTP_ 前綴。 因此,一個叫作 X-Bender 的頭部將轉換成 META 中的 HTTP_X_BENDER 鍵。 ⑧、HttpRequest.FILES 一個相似於字典的對象,包含全部的上傳文件信息。 FILES中的每一個鍵爲<input type="file" name="" /> 中的name,值則爲對應的數據。 注意,FILES 只有在請求的方法爲POST 且提交的<form> 帶有enctype="multipart/form-data" 的狀況下才會包含數據。不然,FILES 將爲一個空的相似於字典的對象。 ⑨、HttpRequest.COOKIES 一個標準的Python 字典,包含全部的cookie。鍵和值都爲字符串。 ⑩、HttpRequest.session 一個既可讀又可寫的相似於字典的對象,表示當前的會話。只有當Django 啓用會話的支持時纔可用。完整的細節參見會話的文檔。 ⑪、HttpRequest.user(用戶認證組件下使用) 一個 AUTH_USER_MODEL 類型的對象,表示當前登陸的用戶。 若是用戶當前沒有登陸,user 將設置爲 django.contrib.auth.models.AnonymousUser 的一個實例。你能夠經過 is_authenticated() 區分它們。 例如: if request.user.is_authenticated(): # Do something for logged-in users. else: # Do something for anonymous users. user 只有當Django 啓用 AuthenticationMiddleware 中間件時纔可用。
b、request經常使用方法
①、HttpRequest.get_full_path() 返回 path,若是能夠將加上查詢字符串,例如:"/music/bands/the_beatles/?print=true"。 ②、HttpRequest.is_ajax() 若是請求是經過XMLHttpRequest 發起的,則返回True,方法是檢查 HTTP_X_REQUESTED_WITH 相應的首部是不是字符串'XMLHttpRequest'。 大部分現代的 JavaScript 庫都會發送這個頭部。若是你編寫本身的 XMLHttpRequest 調用(在瀏覽器端),你必須手工設置這個值來讓 is_ajax() 能夠工做。 若是一個響應須要根據請求是不是經過AJAX 發起的,而且你正在使用某種形式的緩存例如Django 的 cache middleware,你應該使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 裝飾你的視圖以讓響應可以正確地緩存。
(3)、HttpResponse對象
響應對象主要有三種形式(其實都是從HttpResponse中抽離出來的,即本質是最後必定響應一個HttpResponse的實例對象):
1)HttpResponse()
2)render()
3)redirect()
①、HttpResponse()
HttpResponse("字符串")括號內直接跟一個具體的字符串做爲響應體,比較直接很簡單。
②、render()
語法:render(request, template_name[, context])
結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象。
參數說明:
request: 用於生成響應的請求對象;
template_name:要使用的模板的完整名稱;
context:添加到模板上下文的一個字典。默認是一個空字典。若是字典中的某個值是可調用的,視圖將在渲染模板以前調用它(這裏也能夠寫成locals(),表明將全部變量傳遞給頁面);
render方法就是將一個模板頁面中的模板語法進行渲染,最終渲染成一個html頁面做爲響應體(render有兩個功能:一個是讀取文件字符串,另外一個是渲染變量)。
③、redirect()
傳遞要重定向的一個硬編碼的URL,例如:
def my_view(request): ... return redirect('/some/url/')
也能夠是一個完整的URL,例如:
def my_view(request): ... return redirect('http://example.com/')
注意:重定向時,當接收到瀏覽器的第一次請求後,若寫了重定向,則至關於告訴瀏覽器再立刻向指定的地址再發送一次,即一共發送了兩次請求。
補充:
1)301和302的區別:
301和302狀態碼都表示重定向,就是說瀏覽器在拿到服務器返回的這個狀態碼後會自動跳轉到一個新的URL地址,這個地址能夠從響應的Location首部中獲取(用戶看到的效果就是他輸入的地址A瞬間變成了另外一個地址B)— 這是它們的共同點;
他們的不一樣在於:301表示舊地址A的資源已經被永久地移除了(這個資源不可訪問了),搜索引擎在抓取新內容的同時也將舊的網址交換爲重定向以後的網址;
302表示舊地址A的資源還在(仍然能夠訪問),這個重定向只是臨時地從舊地址A跳轉到地址B,搜索引擎會抓取新的內容而保存舊的網址。SEO(搜索引擎優化)302好於301。
2)重定向的緣由:
(1)網站調整(如改變網頁目錄結構);
(2)網頁被移到一個新地址;
(3)網頁擴展名改變(如應用須要把.php改爲.Html或.shtml);
這種狀況下,若是不作重定向,則用戶收藏夾或搜索引擎數據庫中舊地址只能讓訪問客戶獲得一個404頁面錯誤信息,訪問流量白白喪失;再者某些註冊了多個域名的網站,也須要經過重定向讓訪問這些域名的用戶自動跳轉到主站點等。
3)用redirect能夠解釋APPEND_SLASH的用法!
Django的seetings.py配置文件中默認沒有 APPEND_SLASH這個參數,但 Django 默認這個參數爲 APPEND_SLASH = True。做用就是自動在url結尾加'/'。
默認地,任何不匹配或尾部沒有斜槓(/)的申請URL,將被重定向至尾部包含斜槓的相同字眼的URL。當seetings.py設置爲 APPEND_SLASH = False 時,訪問 http://example.com/hello 返回 404。
三、Django的模板層
你可能已經注意到上面視圖層的例子中返回文本的方式有點特別,也就是說,HTML被直接硬編碼在python代碼中,以下:
from django.shortcuts import render,HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
儘管這種方式便於解釋視圖是如何工做的,但直接將HTML硬編碼到你的視圖裏卻並非一個好主意。 讓咱們來看一下爲何:
1)對頁面設計進行的任何改變都必須對 Python 代碼進行相應的修改。 站點設計的修改每每比底層 Python 代碼的修改要頻繁得多,所以若是能夠在不進行 Python 代碼修改的狀況下變動設計,那將會方便得多;
2)Python 代碼編寫和 HTML 設計是兩項不一樣的工做,大多數專業的網站開發環境都將他們分配給不一樣的人員(甚至不一樣部門)來完成。設計者和HTML/CSS的編碼人員不該該被要求去編輯Python的代碼來完成他們的工做;
3)程序員編寫 Python代碼和設計人員製做模板兩項工做同時進行的效率是最高的,遠勝於讓一我的等待另外一我的完成對某個既包含 Python又包含 HTML 的文件的編輯工做;
基於這些緣由,將頁面的設計和Python的代碼分離開會更乾淨簡潔更容易維護。咱們可使用 Django的 模板系統 (Template System)來實現這種模式,這就是下面要具體討論的問題。
Python的模板:HTML代碼 + 模板語法
def current_time(req): # ===============原始的視圖函數=============== # import datetime # now = datetime.datetime.now() # html = "<html><body>如今時刻:<h1>%s.</h1></body></html>" %now # ==========django模板修改的視圖函數========== # from django.template import Template,Context # now = datetime.datetime.now() # t = Template('<html><body>如今時刻是:<h1>{{current_date}}</h1></body></html>') # t = get_template('current_datetime.html') # c = Context({'current_date':str(now)}) # html = t.render(c) # return HttpResponse(html) # 另外一種寫法(推薦) import datetime now = datetime.datetime.now() return render(req, 'current_datetime.html', {'current_date': str(now)[:19]})
學習模板層就要學習Django的模板語法,一共有兩種:
1){{ var_name }} --- 渲染變量;
2){% %} --- 渲染標籤;
(1)、模板語法之變量 - 深度查詢
在 Django 模板中遍歷複雜數據結構的關鍵是句點字符, 語法:{{var_name}},以下示例:
views.py文件中代碼:
from django.shortcuts import render def index(request): import datetime s = "hello" # 字符串 lst = [111, 222, 333] # 列表 dic = {"name": "yuan", "age": 18} # 字典 date = datetime.date(1993, 5, 2) # 日期對象 class Person(object): def __init__(self, name): self.name = name person_yuan = Person("yuan") # 自定義類對象 person_egon = Person("egon") person_alex = Person("alex") person_list = [person_yuan, person_egon, person_alex] return render(request, "index.html", {"s": s, "l": lst, "dic": dic, "date": date, "person_list": person_list})
templates中的index.html模板文件代碼:
<h4>{{ s }}</h4> <h4>列表:{{ lst.0 }}</h4> <h4>列表:{{ lst.2 }}</h4> <h4>字典:{{ dic.name }}</h4> <h4>日期:{{ date.year }}</h4> <h4>類對象列表:{{ person_list.0.name }}</h4>
注意:句點符也能夠用來引用對象的方法(由於引用時不加括號,因此只能引用無參數方法)。
(2)、模板語法之變量 - 過濾器
語法:{{obj|filter_name:param}}
①、default
若是一個變量是false或者爲空,使用給定的默認值。不然,使用變量的值。例如:
{{ value|default:"nothing" }}
②、length
返回值的長度。它對字符串和列表都起做用。例如:{{ value|length }}
若是 value 是 ['a', 'b', 'c', 'd'],那麼輸出是 4。
③、filesizeformat
將值格式化爲一個「人類可讀的」文件尺寸(例如'13 KB','4.1 MB','102 bytes'等等),例如:
{{ value|filesizeformat }}
若是 value 是 123456789,輸出將會是 117.7 MB。
④、date
若是 value=datetime.datetime.now(),例如:
{{ value|date:"Y-m-d" }} 則輸出相似2018-10-22日期格式
⑤、slice
若是 value="hello world",則{{ value|slice:"2:-1" }},輸出"llo worl"
⑥、truncatechars
若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾。例如{{ value|truncatechars:9 }},將截取6個字符 + ...①
⑦、truncatewords
截取單詞,相似truncatechars
⑧、safe
Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,緣由顯而易見,這樣是爲了安全。可是有的時候咱們可能不但願這些HTML元素被轉義,好比咱們作一個內容管理系統,後臺添加的文章中是通過修飾的,這些修飾多是經過一個相似於FCKeditor編輯加註了HTML修飾符的文本,若是自動轉義的話顯示的就是保護HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,若是是一個單獨的變量咱們能夠經過過濾器「|safe」的方式告訴Django這段代碼是安全的,沒必要轉義。好比:
value = "<a href="">點擊</a>"
{{ value|safe }}
這裏簡單介紹一些經常使用的模板的過濾器,更多詳見
(3)、模板語法之渲染標籤
標籤渲染看起來像是這樣的: {% tag %}。渲染標籤語法比渲染變量語法複雜一點:一些在輸出中建立文本,一些經過循環或邏輯來控制流程,一些加載其後的變量將使用到的額外信息到模版中。渲染標籤須要開始和結束標籤(例如{% tag %} ... 內容 ... {% endtag %})。
示例一:for循環遍歷一個列表
{% for person in person_list %} <p>{{ person.name }}</p> {% endfor %}
注:能夠利用{% for obj in list reversed %}反向實現循環。
示例二:for循環遍歷一個字典
{% for key,val in dic.items %} <p>{{ key }}:{{ val }}</p> {% endfor %} 注:循環序號能夠經過{{ forloop }}顯示,以下: forloop.counter }} -- The current iteration of the loop (1-indexed) forloop.counter0 -- The current iteration of the loop (0-indexed) forloop.revcounter -- The number of iterations from the end of the loop (1-indexed) forloop.revcounter0 -- The number of iterations from the end of the loop (0-indexed) forloop.first -- True if this is the first time through the loop forloop.last -- True if this is the last time through the loop
示例三:if控制語句標籤
{ % if num > 100 or num < 0 %} <p>無效</p> { % elif num > 80 and num < 100 %} <p>優秀</p> { % else %} <p>湊活吧</p> { % endif %}
說明:{% if %}會對一個變量求值,若是它的值是「True」(存在、不爲空、且不是boolean類型的false值),對應的內容塊會輸出。
示例四:with語句標籤
{% with total=business.employees.count %}
{{ total }} employee {{ total|pluralize }} {% endwith %}
說明:使用一個簡單地名字緩存一個複雜的變量,當你須要使用一個「昂貴的」方法(好比訪問數據庫)不少次的時候是很是有用的。
示例五:{{ csrf_token }} -- 這個標籤用於跨站請求僞造保護
上篇中咱們提到了當進行post請求時,會發生forbidden錯誤,那是當瀏覽器發送post請求時,除了攜帶用戶想提交的數據以外,服務器還要求瀏覽器攜帶一個服務器以前發送的標識做爲通行證,用來標識該訪問是一個正經常使用戶,因此直接發送post請求而不攜帶那個特定標識時,會被服務器拒絕,因此咱們除了能夠採起上篇中提到註釋掉settings.py文件中的'django.middleware.csrf.CsrfViewMiddleware',還能夠在form表單中添加標籤{{ csrf_token }},會自動生成一個惟一標識。
示例六:for … empty語句標籤
{% for person in person_list %} <p>{{ person.name }}</p> {% empty %} <p>sorry,no person here</p> {% endfor %}
說明:for 標籤帶有一個可選的{% empty %} 從句,以便在給出的組是空的或者沒有被找到時,能夠有所操做。
(5)、模板繼承
Django模版引擎中最強大也是最複雜的部分就是模版繼承了。模版繼承可讓咱們建立一個基本的「骨架」模版,它包含咱們站點中的所有元素,而且能夠定義可以被子模版覆蓋的 block 。
經過從下面這個例子開始,能夠容易的理解模板繼承:
<!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>
這個模版,咱們把它叫做base.html,它定義了一個能夠用於兩列排版頁面的簡單HTML骨架。「子模版」的工做是用它們的內容填充這個模板中的block。在這個例子中,block 標籤訂義了三個能夠被子模版內容填充的block。block 告訴模版引擎:子模版可能會覆蓋掉模版中的這些位置。
子模版可能看起來是這樣的:
{% 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 %}
extends標籤是這裏的關鍵。它告訴模版引擎,這個模版「繼承」了另外一個模版。當模版系統處理這個模版時,首先,它將定位父模版(在此例中,就是「base.html」),而後,模版引擎將注意到 base.html 中的三個block標籤,並用子模版中的內容來替換這些block。根據 blog_entries 的值,輸出可能看起來是這樣的:
<!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>
注意,子模版並無定義sidebar block,因此係統使用了父模版中的值。父模版的{% block %}標籤中的內容老是被用做備選內容。這種方式使代碼獲得最大程度的複用,而且使得添加內容到共享的內容區域更加簡單,例如,部分範圍內的導航。
下面是使用繼承的一些提示:
1)若是你在模版中使用{% extends %}標籤,它必須是這個模版中的第一個標籤。不然,模版繼承將沒法工做。
2)在base模版中設置越多的{% block %}標籤越好。請記住,子模版沒必要定義所有父模版中的block,因此,你能夠在大多數block中填充合理的默認內容,而後,只定義你須要的那一個。多一點鉤子(block)總比少一點好。
3)若是你發現本身在大量的模版中複製內容,那可能意味着你應該把內容移動到父模版中的一個 {% block %} 中。
4)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.
5)爲了更好的可讀性,你也能夠給你的 {% endblock %} 標籤一個 名字 。例如:
{% block content %}
{% endblock content %}
在大型模版中,這個方法幫你清楚的看到哪個{% block %}標籤被關閉了。
6)不能在一個模版中定義多個相同名字的 block 標籤。
四、其餘
(1)、表單提交的action問題
form表單中的action不寫值的話默認提交到當前頁面路徑,寫相對路徑的話當前url的域名 : 端口號和action中的相對路徑拼接就是表單提交的url。