昨日內容回顧:php
1. socket建立服務器 2. http協議: 請求協議 請求首行 請求方式 url?a=1&b=2 協議 請求頭 key:value 請求體 a=1&b=2(只有post請求才有請求體) 響應協議 響應首行 協議 狀態碼 文本 響應頭 key:value 響應體 html字符串 3. wsgiref模塊(基於wsgi協議) 功能: 1. 按着http協議請求格式解析請求數據----envision:{} 2. 按着http協議響應格式封裝響應數據----response 基於wsgiref實現了一個簡單web框架 1. urls : 存放路由關係 views: 存放視圖函數 templates: 存放html文件 wsgi-sever:啓動文件
Web服務器開發領域裏著名的MVC模式,所謂MVC就是把Web應用分爲模型(M),控制器(C)和視圖(V)三層,他們之間以一種插件式的、鬆耦合的方式鏈接在一塊兒,模型負責業務對象與數據庫的映射(ORM),視圖負責與用戶的交互(頁面),控制器接受用戶的輸入調用模型和視圖完成用戶的請求,其示意圖以下所示:css
mvc主要用於web框架,經常使用的開發語言,有java,php,node.js等等。html
web框架應用最普遍就是PHP了,它只能作web開發,並且開發效率很快。java
Django的MTV模式本質上和MVC是同樣的,也是爲了各組件間保持鬆耦合關係,只是定義上有些許不一樣,Django的MTV分別是值:node
Model(模型):和數據庫相關的,負責業務對象與數據庫的對象(ORM)python
Template(模板):放全部的html文件web
模板語法:目的是將白變量(數據庫的內容)如何巧妙的嵌入到html頁面中正則表達式
View(視圖):負責業務邏輯,並在適當的時候調用Model和Templateshell
除了以上三層以外,還須要一個URL分發器,它的做用是將一個個URL的頁面請求分發給不一樣的View處理,View再調用相應的Model和Template,MTV的響應模式以下所示:數據庫
通常是用戶經過瀏覽器向咱們的服務器發起一個請求(request),這個請求回去訪問視圖函數,(若是不涉及到數據調用,那麼這個時候視圖函數返回一個模板也就是一個網頁給用戶),視圖函數調用模型,模型去數據庫查找數據,而後逐級返回,視圖函數把返回的數據填充到模板中空格中,最後返回網頁給用戶。
這裏面最難的部分就是model,後面會慢慢講到。
django 有一個ORM,它是專門來操做數據庫的。這套語法,須要大量練習才能掌握。
MVC: M : model (與數據庫打交道) V : views (存放html文件) C : Controller(邏輯控制部分) MTV M : model (與數據庫打交道) T : templates (存放html文件) V : views (邏輯處理) + 路由控制層(分發哪個路徑由哪個視圖函數處理),它沒有單獨的分層。它做爲URL分發器,將url請求分發給不一樣的view處理
pip3 install django == 2.1.1 ---下載一個最新版本
windows用戶,以管理員身份打開一個cmd窗口。進入一個空目錄,運行如下命令:
E:\python_script\django框架\day2>django-admin startproject mysite
當前目錄下會生成mysite的工程,目錄結構以下:
mysite/ ├── manage.py └── mysite ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
manage.py ----- Django項目裏面的工具,經過它能夠調用django shell和數據庫等。
#manage.py .啓動文件,與項目交互的文件
settings.py ---- 包含了項目的默認設置,包括數據庫信息,調試標誌以及其餘一些工做的變量。
urls.py ----- 負責把URL模式映射到應用程序。
manage.py : 它不關是啓動文件,他仍是與Django交互的文件.好比:
python manage.py runserver : 運行項目
python manage.py startapp : 建立應用
若是運行項目時,不指定端口,默認監聽本機的8000端口。
#進入mysite目錄 E:\python_script\django框架\day2>cd mysite #建立應用blog E:\python_script\django框架\day2\mysite>python manage.py startapp blog
目錄結構以下:
mysite/ ├── blog │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py ├── manage.py └── mysite ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
views.py---存放視圖函數
models--與數據庫打交道
還有一個目錄templates,它是用來存放html文件的,下面會講到。
從上面的目錄結構能夠看出,mysite目錄下有一個blog。那麼頂層的mysite,叫作 項目。底層的blog叫作應用。
好比微信是一個項目。聊天,朋友圈,支付...都是應用。
項目是必須包含應用的,項目能夠包含多個應用。
mysite下的mysite,是全局文件,它有2個全局配置文件,一個是settings.py(項目配置文件),一個是urls.py(路由控制文件)。
wsgi.py是封裝socket,用來接收和響應請求的。這個文件,歷來都不須要動。
E:\python_script\django框架\day2\mysite>python manage.py runserver 8080 Performing system checks... System check identified no issues (0 silenced). You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions. Run 'python manage.py migrate' to apply them. June 21, 2018 - 19:33:29 Django version 2.0.6, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8080/ Quit the server with CTRL-BREAK.
這樣咱們的django就啓動起來了!當咱們訪問:http://127.0.0.1:8080/時就能夠看到:
URL配置(URLconf)就像Django所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函數之間的映射表;
你就是以這種方式告訴Django,對於這個URL調用這段代碼,對於那個URL調用那段代碼。
''' urlpatterns = [ url(正則表達式, views視圖函數,參數,別名), ] 參數說明: 一個正則表達式字符串 一個可調用對象,一般爲一個視圖函數或一個指定視圖函數路徑的字符串 可選的要傳遞給視圖函數的默認參數(字典形式) 一個可選的name參數 '''
1. 簡單的路由配置
經過正則分組獲取url中的動態參數
(如下配置是django1x版本,因此l是url;2x版本則是path)
from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]
注意:
1) 若要從URL中捕獲一個值,只須要在它周圍放置一對圓括號
2) 不須要添加一個前導的反斜槓,由於每一個URL都有.例如應該是^articles
而不是 ^/articles
。
3) 每一個正則表達式前面的'r' 是可選的可是建議加上。它告訴Python 這個字符串是「原始的」 —— 字符串中任何字符都不該該轉義
實例:
''' 一些請求的例子: /articles/2005/03/ 請求將匹配列表中的第三個模式。Django 將調用函數views.month_archive(request, '2005', '03')。 /articles/2005/3/ 不匹配任何URL 模式,由於列表中的第三個模式要求月份應該是兩個數字。 /articles/2003/ 將匹配列表中的第一個模式不是第二個,由於模式按順序匹配,第一個會首先測試是否匹配。請像這樣自由插入一些特殊的狀況來探測匹配的次序。 /articles/2003 不匹配任何一個模式,由於每一個模式要求URL 以一個反斜線結尾。 /articles/2003/03/03/ 將匹配最後一個模式。Django 將調用函數views.article_detail(request, '2003', '03', '03')。 '''
2. 有名分組
給分組起一個名字,實現關鍵字傳參
上面的示例使用簡單的、沒有命名的正則表達式組(經過圓括號)來捕獲URL 中的值並以位置 參數傳遞給視圖。在更高級的用法中,可使用命名的正則表達式組來捕獲URL 中的值並以關鍵字 參數傳遞給視圖。
在Python 正則表達式中,命名正則表達式組的語法是(?P<name>pattern)
,其中name
是組的名稱,pattern
是要匹配的模式。
下面是以上URLconf 使用命名組的重寫:
from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), ]
有名分組和無名分組:
from app02 import views from django.conf.urls import url urlpatterns = [ #無名分組 url(r'^article/\d{4}', views.year) , url(r'^article/(\d{4})$', views.year2), 若是有多個匹配同樣的時候,誰放在上面就匹配誰,上面的就會把下面的覆蓋了 正則加上括號,就是分組,會把分組的內容做爲year2函數的參數傳進去 url(r'^article/(\d{4})/(\d{2})$', views.year_month), # 有名分組(就是給分組起個名字,這樣定義的好處就是按照關鍵字參數去傳參了,指名道姓的方式) url(r'^article/(?P<year>\d{4})/(?P<month>\d{2})$', views.year_month_hasname) ]
這個實現與前面的實例徹底相同,只有一個細微的差異: 捕獲的值做爲關鍵字參數而不是位置參數傳遞給視圖函數.例如:
''' /articles/2005/03/ 請求將調用views.month_archive(request, year='2005', month='03')函數,而不是views.month_archive(request, '2005', '03')。 /articles/2003/03/03/ 請求將調用函數views.article_detail(request, year='2003', month='03', day='03')。 '''
在實際應用中,這意味你的URLconf 會更加明晰且不容易產生參數順序問題的錯誤 —— 你能夠在你的視圖函數定義中從新安排參數的順序。固然,這些好處是以簡潔爲代價;
3. 分發
把每個app本身的url分發各自的路由文件中
mysite1 爲一個django工程 cmdb爲一個項目 dashboard爲一個項目 在mysite1工程下的urls.py中定義以下: from django.conf.urls import url,include from cmdb.views import cmdb_index,login,home from dashboard import views #在兩個項目裏分別建立本身的url.py,在本身的url.py中定義url規則,這樣就能夠解決都在工程下的urls.py中定義混亂的問題 #使用includ關鍵字將兩個項目的url加載進來 urlpatterns = [ url(r'cmdb', include("cmdb.url")), url(r'dashboard', include("dashboard.url")) ] ------------------------------------------------------------ cmdb項目下的url.py文件: from django.conf.urls import url from django.contrib import admin from cmdb import views urlpatterns = [ url(r'login', views.login) ] ------------------------------------------------------------ dashboard項目下的url.py文件: from django.conf.urls import url from django.contrib import admin from dashboard import views urlpatterns = [ url(r'login', views.login) ]
4.反向解析:
不要硬編碼url,經過別名解析url
在使用Django 項目時,一個常見的需求是得到URL 的最終形式,以用於嵌入到生成的內容中(視圖中和顯示給用戶的URL等)或者用於處理服務器端的導航(重定向等)。人們強烈但願不要硬編碼這些URL(費力、不可擴展且容易產生錯誤)或者設計一種與URLconf 絕不相關的專門的URL 生成機制,由於這樣容易致使必定程度上產生過時的URL。
在須要URL 的地方,對於不一樣層級,Django 提供不一樣的工具用於URL 反查:
django.core.urlresolvers.reverse()
函數。urls.py:
from django.conf.urls import url from . import views urlpatterns = [ #... url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'), #... ]
在模板中:
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a> <ul> {% for yearvar in year_list %} <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li> {% endfor %} </ul>
在python中:
from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect def redirect_to_year(request): # ... year = 2006 # ... return HttpResponseRedirect(reverse('news-year-archive', args=(year,))) # 同redirect("/path/")
5.名稱空間
命名空間(英語:Namespace)是表示標識符的可見範圍。一個標識符可在多個命名空間中定義,它在不一樣命名空間中的含義是互不相干的。這樣,在一個新的命名空間中可定義任何標識符,它們不會與任何已有的標識符發生衝突,由於已有的定義都處於其它命名空間中。
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^app01/', include("app01.urls",namespace="app01")), url(r'^app02/', include("app02.urls",namespace="app02")), ]
urlpatterns = [ url(r'^index/', index,name="index"), ]
urlpatterns = [ url(r'^index/', index,name="index"), ]
from django.core.urlresolvers import reverse def index(request): return HttpResponse(reverse("app01:index"))
from django.core.urlresolvers import reverse def index(request): return HttpResponse(reverse("app02:index"))
一個視圖函數,簡稱視圖,是一個簡單的Python 函數,它接受Web請求而且返回Web響應。響應能夠是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片. . . 是任何東西均可以。不管視圖自己包含什麼邏輯,都要返回響應。代碼寫在哪裏也無所謂,只要它在你的Python目錄下面。除此以外沒有更多的要求了——能夠說「沒有什麼神奇的地方」。爲了將代碼放在某處,約定是將視圖放置在項目或應用程序目錄中的名爲views.py的文件中。
一個簡單的視圖函數
-----views.py
from django.shortcuts import render,HttpResponse # Create your views here. def year(request): # request參數請求全部的參數,這個參數必定要有 return HttpResponse("ok") #每個視圖函數必須有return def year2(request,year): print(year) return HttpResponse("hello") #返回的必定是一個字符串,若是你想return純字符串,就用HttpResponse方法 def year_month(request,year,month): print(year,month) # 返回的是匹配的年和月拼接的結果 return HttpResponse(year+month) # def year_month_hasname(request,month,year): # return HttpResponse("ok") print(year,month) return HttpResponse("month是:%s,year是:%s"%(month,year))
注意: 視圖會返回一個HttpReponse對象,其中包含生成的響應.每一個視圖函數都負責返回一個HttpReponse對象.
屬性:
''' path: 請求頁面的全路徑,不包括域名 method: 請求中使用的HTTP方法的字符串表示。全大寫表示。例如 if req.method=="GET": do_something() elif req.method=="POST": do_something_else() GET: 包含全部HTTP GET參數的類字典對象 POST: 包含全部HTTP POST參數的類字典對象 COOKIES: 包含全部cookies的標準Python字典對象;keys和values都是字符串。 FILES: 包含全部上傳文件的類字典對象;FILES中的每個Key都是<input type="file" name="" />標籤中 name屬性的值,FILES中的每個value同時也是一個標準的python字典對象,包含下面三個Keys: filename: 上傳文件名,用字符串表示 content_type: 上傳文件的Content Type content: 上傳文件的原始內容 user: 是一個django.contrib.auth.models.User對象,表明當前登錄的用戶。若是訪問用戶當前 沒有登錄,user將被初始化爲django.contrib.auth.models.AnonymousUser的實例。你 能夠經過user的is_authenticated()方法來辨別用戶是否登錄: if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware 時該屬性纔可用 session: 惟一可讀寫的屬性,表明當前會話的字典對象;本身有激活Django中的session支持時該屬性纔可用。 '''
render(request, template_name[, context])
結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象。
參數: request: 用於生成響應的請求對象。 template_name:要使用的模板的完整名稱,可選的參數 context:添加到模板上下文的一個字典。默認是一個空字典。若是字典中的某個值是可調用的,視圖將在渲染模板以前調用它。 content_type:生成的文檔要使用的MIME類型。默認爲DEFAULT_CONTENT_TYPE 設置的值。 status:響應的狀態碼。默認爲200。
傳遞要重定向的一個硬編碼的URL
1
2
3
|
def
my_view(request):
...
return
redirect(
'/some/url/'
)
|
也能夠是一個完整的URL:
1
2
3
|
def
my_view(request):
...
return
redirect(
'http://example.com/'
)
|
key:兩次請求
1)301和302的區別。 301和302狀態碼都表示重定向,就是說瀏覽器在拿到服務器返回的這個狀態碼後會自動跳轉到一個新的URL地址,這個地址能夠從響應的Location首部中獲取 (用戶看到的效果就是他輸入的地址A瞬間變成了另外一個地址B)——這是它們的共同點。 他們的不一樣在於。301表示舊地址A的資源已經被永久地移除了(這個資源不可訪問了),搜索引擎在抓取新內容的同時也將舊的網址交換爲重定向以後的網址; 302表示舊地址A的資源還在(仍然能夠訪問),這個重定向只是臨時地從舊地址A跳轉到地址B,搜索引擎會抓取新的內容而保存舊的網址。 SEO302好於301 2)重定向緣由: (1)網站調整(如改變網頁目錄結構); (2)網頁被移到一個新地址; (3)網頁擴展名改變(如應用須要把.php改爲.Html或.shtml)。 這種狀況下,若是不作重定向,則用戶收藏夾或搜索引擎數據庫中舊地址只能讓訪問客戶獲得一個404頁面錯誤信息,訪問流量白白喪失;再者某些註冊了多個域名的 網站,也須要經過重定向讓訪問這些域名的用戶自動跳轉到主站點等。 關於301與302
用redirect能夠解釋APPEND_SLASH的用法!
1) HttpReponse()
2) render()
3) redirect()
python的模板:HTML代碼+模板語法
模版包括在使用時會被值替換掉的 變量,和控制模版邏輯的 標籤。
1
|
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]})
1. 模板語法之變量
在 Django 模板中遍歷複雜數據結構的關鍵是句點字符, 語法:
1
|
{{var_name}}
|
views.py:
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 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",{"l":l,"dic":dic,"date":date,"person_list":person_list})
template:
1
2
3
4
5
6
|
<h4>{{s}}<
/
h4>
<h4>列表:{{ l.
0
}}<
/
h4>
<h4>列表:{{ l.
2
}}<
/
h4>
<h4>字典:{{ dic.name }}<
/
h4>
<h4>日期:{{ date.year }}<
/
h4>
<h4>類對象列表:{{ person_list.
0.name
}}<
/
h4>
|
注意:句點符也能夠用來引用對象的方法(無參數方法):
1
|
<h4>字典:{{ dic.name.upper }}<
/
h4>
|
2. 模板之過濾器
語法:
{{obj|filter__name:param}}
default
若是一個變量是false或者爲空,使用給定的默認值。不然,使用變量的值。例如:
1
|
{{ value|default:
"nothing"
}}
|
返回值的長度。它對字符串和列表都起做用。例如:
1
|
{{ value|length }}
|
若是 value 是 ['a', 'b', 'c', 'd'],那麼輸出是 4。
filesizeformat
將值格式化爲一個 「人類可讀的」 文件尺寸 (例如 '13 KB'
, '4.1 MB'
, '102 bytes'
, 等等)。例如:
1
|
{{ value|filesizeformat }}
|
若是 value
是 123456789,輸出將會是 117.7 MB
。
若是 value=datetime.datetime.now()
1
|
{{ value|date:
"Y-m-d"
}}
|
模板過濾器slice, 取變量前 N 個字符,可用於中文
若是 value="hello world"
1
|
{{ value|
slice
:
"2:-1"
}}
|
模板過濾器 truncatewords ,取這個模板變量的前 N 個字符,只能用於英文
1
|
{{ value|truncatewords:10
}}
|
若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾。
參數:要截斷的字符數
例如:
1
|
{{ value|truncatechars:
9
}}
|
Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,緣由顯而易見,這樣是爲了安全。可是有的時候咱們可能不但願這些HTML元素被轉義,好比咱們作一個內容管理系統,後臺添加的文章中是通過修飾的,這些修飾多是經過一個相似於FCKeditor編輯加註了HTML修飾符的文本,若是自動轉義的話顯示的就是保護HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,若是是一個單獨的變量咱們能夠經過過濾器「|safe」的方式告訴Django這段代碼是安全的沒必要轉義。好比:
1
|
value
=
"<a href="
">點擊</a>"
|
1
|
{{ value|safe}}
|
3. 模板之標籤
標籤看起來像是這樣的: {% tag %}
。標籤比變量更加複雜:一些在輸出中建立文本,一些經過循環或邏輯來控制流程,一些加載其後的變量將使用到的額外信息到模版中。一些標籤須要開始和結束標籤 (例如{% tag %} ...
標籤 內容 ... {% endtag %})。
遍歷每個元素:
{% 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 %}
for 標籤帶有一個可選的{% empty %} 從句,以便在給出的組是空的或者沒有被找到時,能夠有所操做。
{% for person in person_list %} <p>{{ person.name }}</p> {% empty %} <p>sorry,no person here</p> {% endfor %} if 標籤
{% if %}會對一個變量求值,若是它的值是「True」(存在、不爲空、且不是boolean類型的false值),對應的內容塊會輸出。
{% if num > 100 or num < 0 %} <p>無效</p> {% elif num > 80 and num < 100 %} <p>優秀</p> {% else %} <p>湊活吧</p> {% endif %}
使用一個簡單地名字緩存一個複雜的變量,當你須要使用一個「昂貴的」方法(好比訪問數據庫)不少次的時候是很是有用的
例如:
{% with total=business.employees.count %} {{ total }} employee{{ total|pluralize }} {% endwith %}
這個標籤用於跨站請求僞造保護
4.自定義標籤和過濾器
一、在settings中的INSTALLED_APPS配置當前app,否則django沒法找到自定義的simple_tag.
二、在app中建立templatetags模塊(模塊名只能是templatetags)
三、建立任意 .py 文件,如:my_tags.py
四、在使用自定義simple_tag和filter的html文件中導入以前建立的 my_tags.py
1
|
{
%
load my_tags
%
}
|
五、使用simple_tag和filter(如何調用)
1
2
3
4
5
6
7
8
9
10
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
.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不能夠
1
2
3
|
{
%
if
num|filter_multi:
30
>
100
%
}
{{ num|filter_multi:
30
}}
{
%
endif
%
}
|
5. 模板繼承(extend)
Django模版引擎中最強大也是最複雜的部分就是模版繼承了。模版繼承可讓您建立一個基本的「骨架」模版,它包含您站點中的所有元素,而且能夠定義可以被子模版覆蓋的 blocks 。
經過從下面這個例子開始,能夠容易的理解模版繼承:
<!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="style.css" /> <title>{% block title %}My amazing site{%/span> 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骨架。「子模版」的工做是用它們的內容填充空的blocks。
在這個例子中, block
標籤訂義了三個能夠被子模版內容填充的block。 block
告訴模版引擎: 子模版可能會覆蓋掉模版中的這些位置。
子模版可能看起來是這樣的:
1
2
3
4
5
6
7
8
9
10
|
{
%
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
的值,輸出可能看起來是這樣的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<!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 %}
標籤中的內容老是被用做備選內容(fallback)。
這種方式使代碼獲得最大程度的複用,而且使得添加內容到共享的內容區域更加簡單,例如,部分範圍內的導航。
這裏是使用繼承的一些提示:
若是你在模版中使用 {% extends %}
標籤,它必須是模版中的第一個標籤。其餘的任何狀況下,模版繼承都將沒法工做。
在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.
爲了更好的可讀性,你也能夠給你的 {% endblock %}
標籤一個 名字 。例如:
1
2
3
|
{
%
block content
%
}
...
{
%
endblock content
%
}
|
在大型模版中,這個方法幫你清楚的看到哪個 {% block %}
標籤被關閉了。
block
標籤。