一 引子
什么是模版系統?這里做一個簡單解釋。要想明白什么是模版系統,那么我們得先分清楚靜態頁面和動態頁面。我們之前學過的都是靜態頁面,所謂的靜態頁面就是瀏覽器向后端發送一個請求,后端接收到這個請求,然后返回給瀏覽器一個html頁面,這個過程不涉及從數據庫取出數據渲染到html頁面上,只是單純的返回一個頁面(數據全部在html頁面上)。而動態頁面就是在給瀏覽器返回html頁面之前,需要后端與數據庫之間進行數據交互,然后將數據渲染到html頁面上在返回給瀏覽器。言外之意靜態頁面不涉及數據庫,動態頁面需要涉及從數據庫取出數據。那么模版系統是什么呢?如果你只是單純的寫靜態頁面,也就沒必有必要用模版系統了,只用動態頁面才需要模版系統。
簡單來說,模版系統就是在html頁面想要展示的數據庫或者后端的數據的標簽上做上特殊的占位(類似於格式化輸出),通過render方法將這些占位的標簽里面的數據替換成你想替換的數據,然后再將替換數據之后的html頁面返回給瀏覽器,這個就是模版系統。
模板渲染的官方文檔
關於模板渲染你只需要記兩種特殊符號(語法):
{{ }}和 {% %}
變量相關的用{{}},邏輯相關的用{%%}。
二、變量
1. 簡單示例
接下來,我們先搭一個簡單流程:瀏覽器訪問https://127.0.0.1:8000:/index,返回一個index.html頁面,我們在views函數中設置一些變量,然后通過模版系統渲染,最終返回給瀏覽器。
url:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^index/',views.index), ]
views:
render第三個參數接受一個字典的形式,通過字典的鍵值對index.html頁面進行渲染,這也就是模塊渲染。
def index(request): name = '太白金星' age = 18 name_list = ['王闊', '天琪', '傻強', '志晨', '健身哥'] dic = {'classname': '人工智能', 'since': 2019} return render(request, 'index.html',{'name': name, 'age': age,'name_list':name_list, 'dic_class':dic})
html:
<!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"> <title>Bootstrap 101 Template</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <h1>你好,世界!</h1> <ul> {# 通過render進行模版語言渲染然后替換成后端的數據,最終發給瀏覽器 #} <li>{{ name }}</li> <li>{{ age }}</li> <li>{{ name_list }}</li> <li>{{ dic_class }}</li> </ul> </body> </html>
最終瀏覽器顯示的結果為:
這樣,你后端這些變量全部都渲染到前端了。
2. 語法
在Django的模板語言中按此語法使用:{{ 變量名 }}。
當模版引擎遇到一個變量,它將計算這個變量,然后用結果替換掉它本身。 變量的命名包括任何字母數字以及下划線 ("_")的組合。 變量名稱中不能有空格或標點符號。
深度查詢據點符(.)在模板語言中有特殊的含義。當模版系統遇到點("."),它將以這樣的順序查詢:
字典查詢(Dictionary lookup)
屬性或方法查詢(Attribute or method lookup)
數字索引查詢(Numeric index lookup)
3. 萬能的點 .
通過簡單示例我們已經知道模版系統對於變量的渲染是如何做到的,非常簡單,接下來我們研究一些深入的渲染,我們不想將整個列表或者字典渲染到html,而是將列表里面的元素、或者字典的某個值渲染到html頁面中,那怎么做呢?就是通過萬能的點。
views:
def index(request): name_list = ['王闊', '天琪', '傻強', '志晨', '健身哥'] dic = {'classname': '人工智能', 'since': 2019} lis = [1, ['冠狀病毒', '武漢加油'],3] # 使用locals是用於測試,實際生產環境中是不可以的。 return render(request, 'index.html', locals())
html:
<!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"> <title>Bootstrap 101 Template</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <h1>你好,世界!</h1> <ul> {# 萬能的點 #} <li>{{ name_list.2 }}</li> <li>{{ dic.classname }}</li> <li>{{ lis.1.0 }}</li> </ul> </body> </html>
瀏覽器的顯示結果:
剛才我們嘗試的數據類型,那么在一切皆對象的python世界中,我們一個對象是否可以通過模版渲染到html頁面中呢?
views:
def index(request): class A: def __init__(self): self.name = 'barry' def func(self): return '太白教你學python' obj = A() return render(request, 'index.html', locals())
html:
<!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"> <title>Bootstrap 101 Template</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <h1>你好,世界!</h1> <ul> {# 萬能的點 #} <li>{{ obj.name }}</li> <li>{{ obj.func }}</li> </ul> </body> </html>
瀏覽器顯示的結果:
如圖所示,對象也是可以通過模版渲染到html頁面中的,但是這里要注意一個點:obj.func是不可以加括號的,所以我們后端設置的函數是不可以有參數的(類中的方法self自動傳遞)。
注意我們直接在js代碼中使用模板語法的時候,模板渲染的時候會有個轉義的動作,將s = ['哈哈','xx']這種數據中的元素的引號變為一個特殊符號:這個我們后面會講到
<script> // 不加safe的話,引號會被轉義。
// var a = {{ s }} // var a = ['哈哈', 'xx']; // console.log(a[0]) // 加上safe就正常了 var a = {{ s|safe }}; console.log(a[0])
// 還要注意,當我們模板渲染的時候,后端返回的數據是字符串的話,我們需要將{{ s }}外面加上引號
比如s = '哈哈'
js中的寫法
var a = '{{ s }}' </script>
三、過濾器
1.什么是過濾器
有的時候我們通過render渲染到html的數據並不是我們最終想要的數據,比如后端向前端傳遞的數據為hello,但是我們html想要顯示為HELLO,當然這個在后端是可以提前處理的,但是諸如此類的需求我們可以通過過濾器解決,過濾器給我們提過了很多便捷的方法,加工你傳遞到html的數據,便於靈活開發。
2.語法
過濾器的語法: {{ value| filter_name:參數 }}
使用管道符"|"來應用過濾器。
例如:{{ name| lower }}會將name變量應用lower過濾器之后再顯示它的值。lower在這里的作用是將文本全都變成小寫。
注意事項:
- 過濾器支持“鏈式”操作。即一個過濾器的輸出作為另一個過濾器的輸入。
- 過濾器可以接受參數,例如:{{ sss|truncatewords:30 }},這將顯示sss的前30個詞。
- 過濾器參數包含空格的話,必須用引號包裹起來。比如使用逗號和空格去連接一個列表中的元素,如:{{ list|join:', ' }}
- '|'左右沒有空格!沒有空格!沒有空格!
Django的模板語言中提供了大約六十個內置過濾器。
3.常用過濾器
default: 如果一個變量是false或者為空,使用給定的默認值。 否則,使用變量的值。
views: a = '' # 沒有變量a或者變量a為空
html: # 顯示啥也沒有 {{ value|default:"啥也沒有"}}
length:返回值的長度,作用於字符串和列表。
views: name_list = ['王闊', '天琪', '傻強', '志晨', '健身哥'] s = '太白金星講師' html: {{ name_list|length }} # 顯示為5 {{s|length }} # 顯示為6
filesizeformat: 將值格式化為一個 “人類可讀的” 文件尺寸 (例如 '13 KB'
, '4.1 MB'
, '102 bytes'
, 等等)。
views: value = 1048576 html: {{ value|filesizeformat }} # 顯示為1.0MB
slice:切片,支持pyhton中可以用切片的所有數據類型
views: name_list = ['王闊', '天琪', '傻強', '志晨', '健身哥'] s = '太白金星講師' html: {{ name_list|slice:'1:3' }} # ['天琪', '傻強'] {{ s|slice:'1::2' }} # '白星師'
date:時間格式化
views: time = datetime.datetime.now() html: {{ t|date:"Y-m-d H:i:s" }} # 2020-02-11 07:31:29
關於時間日期的可用的參數(除了Y,m,d等等)還有很多,有興趣的可以去查查看看。
truncatechars:如果字符串字符多於指定的字符數量,那么會被截斷。截斷的字符串將以可翻譯的省略號序列(“...”)結尾。
參數:截斷的字符數
views: describe = '1999年3月,馬雲正式辭去公職,后來被稱為18羅漢的馬雲團隊回到杭州,湊夠50萬元人民幣' html: {{ describe|truncatechars:9 }} # 1999年3... # 截斷9個字符,三個點也算三個字符
這個我們在瀏覽網頁時經常見到,描述的內容很多,只能用...顯示,比如:
truncatewords:在一定數量的字后截斷字符串,是截多少個單詞。
views: words = 'i love you my country china' html: {{ words|truncatewords:3 }} # i love you...
cut: 移除value中所有的與給出的變量相同的字符串
views:
words = 'i love you my country china' html: {{ words|cut:3 }} # iloveyou
join: 設定連接符將可迭代對象的元素連接在一起與字符串的join方法相同。
views: name_list = ['王闊', '天琪', '傻強', '志晨', '健身哥'] dic = {'name':'太白','age': 18} tu = (1, 2, 3) html: <li>{{ name_list|join:'_'}}</li> <li>{{ dic|join:','}}</li> <li>{{ tu|join:'+'}}</li> ''' 王闊_天琪_傻強_志晨_健身哥 name,age 1+2+3 '''
safe
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攻擊的根本途徑,例如博客園:
timesince(了解)
將日期格式設為自該日期起的時間(例如,“4天,6小時”)。
采用一個可選參數,它是一個包含用作比較點的日期的變量(不帶參數,比較點為現在)。 例如,如果since_12是表示2012年6月28日日期實例,並且comment_date是2018年3月1日日期實例:
views: year_12 = datetime.datetime.now().replace(year=2012, month=6, day=28) year_18 = datetime.datetime.now().replace(year=2018, month=3, day=1) html: <li>{{ year_12|timesince:year_18}}</li>
'''
5 years, 8 months
'''
如果year_18不寫,默認就是距現在的時間段。
timeuntil(了解)
似於timesince,除了它測量從現在開始直到給定日期或日期時間的時間。 例如,如果今天是2006年6月1日,而conference_date是保留2006年6月29日的日期實例,則{{ conference_date | timeuntil }}將返回“4周”。
使用可選參數,它是一個包含用作比較點的日期(而不是現在)的變量。 如果from_date包含2006年6月22日,則以下內容將返回“1周”:
{{ conference_date|timeuntil:from_date }}
這里簡單介紹一些常用的模板的過濾器,更多詳見
更多內置過濾器(此鏈接頁面最下面的內置過濾器):https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#filters
四、標簽Tags
現在我們已經可以從后端通過模版系統替換掉前端的數據了,但是如果只是替換掉數據,確實不夠靈活,比如,我們要想在前端頁面展示可迭代對象name_list = ['王闊', '天琪', '傻強', '志晨', '健身哥']每個元素,你如和展示呢?
# 前端頁面 <ul> <li>{{ name_list.0 }}</li> <li>{{ name_list.1 }}</li> <li>{{ name_list.2 }}</li> <li>{{ name_list.3 }}</li> </ul>
這樣寫明顯很low,我們要是可以用上for循環就好了。Django這么強大的框架,不可能想不到這點的,這里模版系統給我們提供了另一種標簽,就是可以在html頁面中進行for循環以及if判斷等等。
標簽看起來像是這樣的: {% tag %}
。標簽比變量更加復雜:一些在輸出中創建文本,一些通過循環或邏輯來控制流程,一些加載其后的變量將使用到的額外信息到模版中。與python語法不同的是:一些標簽需要開始和結束標簽 (例如{% tag %} ...
標簽 內容 ... {% endtag %})。
學習下面幾種標簽之前,我們要重新寫一個url、views以及html,方便分類學習不與上面的變量產生沖突。
urls: url(r'^tags/',views.tags), views: def tags(request): num = 10
value = '' name_list = ['王闊', '天琪', '傻強', '志晨', '健身哥'] dic = {'name': '太白金星', 'age': 18} return render(request, 'tags.html', locals()) 先創建一個簡單的tags.html即可。
for標簽
基本語法:
{% for 變量 in render的可迭代對象 %}
{{ 變量 }}
{% endfor %}
例如:
{% for foo in name_list %}
{{ foo }}
{% endfor %}
便捷用法:
遍歷每一個元素: 寫個for,然后 tab鍵自動生成for循環的結構,循環很基礎,就這么簡單的用,沒有什么break之類的,復雜一些的功能,你要通過js。可以利用{% for obj in list reversed %}反向完成循環。
遍歷一個列表
<ul> {% for foo in name_list %} <li>{{ foo }}</li> {% endfor %} </ul>
反向遍歷一個列表
{% for foo in name_list reversed %} <li>{{ foo }}</li> {% endfor %}
遍歷一個字典:有items、keys、values參數
<ul> {% for key,value in dic.items %} <li>{{ key }}: {{ value }}</li> {% endfor %} {% for key in dic.keys %} <li>{{ key }}</li> {% endfor %} {% for value in dic %} <li>{{ value }}</li> {% endfor %} </ul>
forloop的使用
模版系統給我們的for標簽還提供了forloop的功能,這個就是獲取循環的次數,有多種用法:
forloop.counter 當前循環的索引值(從1開始),forloop是循環器,通過點來使用功能
forloop.counter0 當前循環的索引值(從0開始)
forloop.revcounter 當前循環的倒序索引值(從1開始)
forloop.revcounter0 當前循環的倒序索引值(從0開始)
forloop.first 當前循環是不是第一次循環(布爾值)
forloop.last 當前循環是不是最后一次循環(布爾值)
forloop.parentloop 本層循環的外層循環的對象,再通過上面的幾個屬性來顯示外層循環的計數等
我們通過name_list示例:
<ul> {% for foo in name_list %} <li>{{ forloop.counter }} {{ foo }}</li> {% endfor %} {% for foo in name_list %} {{ forloop.counter0 }} <li>{{ foo }}</li> {% endfor %} </ul>
forloop.counter0數字與元素不在一行是因為我html標簽擺放的問題,與方法無關。
{% for foo in name_list %} <li>{{ forloop.revcounter }} {{ foo }}</li> {% endfor %}
{% for foo in name_list %} <li>{{ forloop.first }} {{ foo }}</li> {% endfor %}
forloop.first、forloop.last多用於下面我們講到if判斷條件。 forloop.parentloop我們講到if標簽在演示。
for...empty...組合
如果遍歷的可迭代對象是空的或者就沒有這個對象,利用這個組合可以提示用戶。
<ul> {% for foo in aaa %} <li>{{ foo }}</li> {% empty %} <li>查詢的內容啥也沒有</li> {% endfor %} {% for foo in value %} <li>{{ foo }}</li> {% empty %} <li>查詢的內容啥也沒有</li> {% endfor %} </ul>
if標簽
基本語法:
{% if %}會對一個變量求值,如果它的值是“True”(存在、不為空、且不是boolean類型的false值),對應的內容塊會輸出。
{% if 條件 %} 結果 <!--不滿足條件,不會生成這個標簽--> {% elif 條件 %} 結果 {% else %} <!--也是在if標簽結構里面的--> 結果 {% endif %}
elif和else一定要在if endif標簽里面,設置多個elif或者沒有elif、有沒有else都可以。
示例:
{% if dic.age > 18 %} <p>可以干點兒該做的事兒了~</p> {% elif dic.age < 18 %} <p>小孩子,懂什么</p> {% else %} <p> 風華正茂的年齡~</p> {% endif %}
條件也可以與過濾功能配合
% if name_list|length > 4 %} <p>列表元素超過4個</p> {% else %} <p>列表元素太少!</p> {% endif %}
條件也可以加邏輯運算符
if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷,注意條件兩邊都有空格。
{% if name_list|length > 4 and '王闊' in name_list %} <p>條件都滿足</p> {% endif %}
with
使用一個簡單地名字緩存一個復雜的變量,多用於給一個復雜的變量起別名,當你需要使用一個“昂貴的”方法(比如訪問數據庫)很多次的時候是非常有用的,記住!等號的左右不要加空格!!
{% with total=business.employees.count %} {{ total }} <!--只能在with語句體內用--> {% endwith %}
{% with business.employees.count as total %} {{ total }} {% endwith %}
forloop.first、forloop.last、forloop.parentloop
當時講for循環時有三個方法,我們沒有嘗試,因為需要與if條件配合。
forloop.first
{% for foo in name_list %} {% if forloop.first %} {{ foo }} {% else %} <p>只有第一次循環打印</p> {% endif %} {% endfor %}
forloop.parentloop : 一定注意!他是返回本此循環的外層循環對象,這個對象可以調用forloop的各種方法進行獲取相應的數據。
測試此方法,我們要在views函數中加一個數據類型:lis = [['A', 'B'], ['C', 'D'], ['E', 'F']]
{% for i in lis %} {% for j in i %} {# <p>{{ forloop.parentloop }}</p>#} <p>{{ forloop.parentloop.counter }} {{ forloop.counter }} {{ j }}</p> {% endfor %} {% endfor %}
注意事項
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的值。
csrf_token標簽
這個標簽是不是非常熟悉?之前我們以post方式提交表單的時候,會報錯,還記得我們在settings里面的中間件配置里面把一個csrf的防御機制給注銷了啊,本身不應該注銷的,而是應該學會怎么使用它,並且不讓自己的操作被forbiden,通過這個標簽就能搞定。
接下來我們重寫構建一個流程:
urls、views、html:

urlpatterns = [ url(r'^login/',views.login), ] from django.shortcuts import render, HttpResponse, redirect def login(request): if request.method == 'GET': return render(request, 'login.html') else: print(request.POST) # 這里我們就不進行驗證了,只是研究csrf_token return HttpResponse('登錄成功!!!') <!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"> <title>Bootstrap 101 Template</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <h3>登錄頁面</h3> <form action="" method="post"> 用戶名:<input type="text" name="username"> 密碼:<input type="text" name="password"> <button>提交</button> </form> </body> </html>
注意:post、get請求不一定非要寫在一個視圖函數中,那么我們之前為什么寫在一個視圖函數中,就是因為post、get都是請求相關的消息,所以我們都用一個視圖函數去處理,你也可以寫在兩個視圖函數中,自己可以嘗試一下。
此時我們開啟項目,通過瀏覽器進行訪問,當你點擊提交時,瀏覽器返回這樣一個畫面:
這就是csrf安全機制給你做出的響應。我們之前都是找到settings給對應的中間件注釋掉,但是現在我們要研究一下如何遵循這個安全機制,只要我們在你的form表單中加上一個csrf_token標簽就行了。
那么這個標簽起到了什么作用呢?他的原理是什么?我們再次刷新這個頁面,看一下源碼:
當我們加上此標簽之后,再次發出get請求,render返回給我們的頁面中多了一個隱藏的input標簽,並且這個標簽里面有個一鍵值對:
鍵:name,值:隨機的一堆密文。 那么這個是干什么用的呢?其實他的流程是這樣的:
說了這么多,目的就是一個:驗證當你post提交請求時,是不是從我給你(你通過get請求的)頁面上提交的數據。
那么接下來,我們寫一個簡單的爬蟲驗證一下:
import requests ret = requests.post('http://127.0.0.1:8000/login/', data={'username': 'taibai', 'password': '123'} ) print(ret.content)
如果你保留這這個驗證,則通過爬蟲是登錄不成功的,只能返回你一個forbidden的html頁面。
如果你將settings那個中間件注釋掉,那么就可以成功訪問了:
五、模版繼承
1. 引子
什么是模版繼承?將這兩個字拆開我們都清楚,模版就是django提供的用於html發送瀏覽器之前,需要在某些標簽進行替換的系統,而繼承我們立馬就會想到這是面向對象的三大特性之一。其實模版繼承就是擁有這兩個特性的模版的高級用法。先不着急直接上知識點,我們用一個例子引出模版繼承。
我們經常訪問一些網站,你會發現只要是一個網站的多個html頁面,他們有一部分是一模一樣的,剩下的部分是本頁面獨有的。比如我們經常使用的博客園:
這個是我博客園的首頁:
然后我們隨機點一篇博客進去:
個人博客園設定了博客園的樣式之后,你所有的博客都是按照這個樣式創建的,在我選擇的主題這里:導航條和側邊欄布局是一樣的。再比如如果是公司內部的xx管理系統,更是如此。我們打開bootstraps網站(起步):
一般管理系統都是這樣的布局,這個就是固定的導航條和側邊欄。無論我點擊側邊欄里的那個按鈕,這兩部分不會更換只會改變中間的內容。
那么接下來我們實現一個這樣的布局。
我們要准備4個html頁面:base.html、menu1.html、menu2.html、menu3.html,這四個頁面的導航條與左側側邊欄一樣,每個頁面對應一個url。並且每個頁面的左側側邊欄菜單一、菜單二、菜單三可以實現跳轉:跳轉到menu1.html、menu2.html、menu3.html三個頁面。而頂端導航條只是樣式即可。接下來借助於Django,我們實現這四個頁面並對應urls可以跑通流程。
urls:
urlpatterns = [ url(r'^base/', views.base), url(r'^menu1/', views.menu1), url(r'^menu2/', views.menu2), url(r'^menu3/', views.menu3), ]
views:
def base(request): return render(request, 'base.html') def menu1(request): return render(request, 'menu1.html') def menu2(request): return render(request, 'menu2.html') def menu3(request): return render(request, 'menu3.html')
html:

base.html: <!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"> <title>Bootstrap 101 Template</title> <style> body{ margin: 0; padding: 0; } .nav{ background-color: black; color: #eaeaea; height: 30px; width: 100%; } .clearfix{ content: ''; display: block; clear: both; } .sidebar{ background-color: #b2b2b2; color: #435dff; width: 20%; height: 1000px; float: left; } .sidebar ul{ margin: 0; } .menu{ width: 80%; float: right; } </style> </head> <body> <div class="nav clearfix"> <a href="">普通洗浴</a> <a href="">盆兒堂</a> <a href="">局部護理</a> <a href="">關於我們</a> <a href="">預約電話</a> <input type="text">搜索 </div> <div class='sidebar'> <ul> <li><a href="/menu1/">菜單一</a></li> <li><a href="/menu2/">菜單二</a></li> <li><a href="/menu3/">菜單三</a></li> </ul> </div> <div class="menu"> 首頁 </div> </body> </html> menu1.html: <!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"> <title>Bootstrap 101 Template</title> <style> body{ margin: 0; padding: 0; } .nav{ background-color: black; color: #eaeaea; height: 30px; width: 100%; } .clearfix{ content: ''; display: block; clear: both; } .sidebar{ background-color: #b2b2b2; color: #435dff; width: 20%; height: 1000px; float: left; } .sidebar ul{ margin: 0; } .menu{ width: 80%; float: right; } </style> </head> <body> <div class="nav clearfix"> <a href="">普通洗浴</a> <a href="">盆兒堂</a> <a href="">局部護理</a> <a href="">關於我們</a> <a href="">預約電話</a> <input type="text">搜索 </div> <div class='sidebar'> <ul> <li><a href="/menu1/">菜單一</a></li> <li><a href="/menu2/">菜單二</a></li> <li><a href="/menu3/">菜單三</a></li> </ul> </div> <div class="menu"> 菜單一首頁 </div> </body> </html> menu2.html: <!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"> <title>Bootstrap 101 Template</title> <style> body{ margin: 0; padding: 0; } .nav{ background-color: black; color: #eaeaea; height: 30px; width: 100%; } .clearfix{ content: ''; display: block; clear: both; } .sidebar{ background-color: #b2b2b2; color: #435dff; width: 20%; height: 1000px; float: left; } .sidebar ul{ margin: 0; } .menu{ width: 80%; float: right; } </style> </head> <body> <div class="nav clearfix"> <a href="">普通洗浴</a> <a href="">盆兒堂</a> <a href="">局部護理</a> <a href="">關於我們</a> <a href="">預約電話</a> <input type="text">搜索 </div> <div class='sidebar'> <ul> <li><a href="/menu1/">菜單一</a></li> <li><a href="/menu2/">菜單二</a></li> <li><a href="/menu3/">菜單三</a></li> </ul> </div> <div class="menu"> 菜單2首頁 </div> </body> </html> menu3.html <!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"> <title>Bootstrap 101 Template</title> <style> body{ margin: 0; padding: 0; } .nav{ background-color: black; color: #eaeaea; height: 30px; width: 100%; } .clearfix{ content: ''; display: block; clear: both; } .sidebar{ background-color: #b2b2b2; color: #435dff; width: 20%; height: 1000px; float: left; } .sidebar ul{ margin: 0; } .menu{ width: 80%; float: right; } </style> </head> <body> <div class="nav clearfix"> <a href="">普通洗浴</a> <a href="">盆兒堂</a> <a href="">局部護理</a> <a href="">關於我們</a> <a href="">預約電話</a> <input type="text">搜索 </div> <div class='sidebar'> <ul> <li><a href="/menu1/">菜單一</a></li> <li><a href="/menu2/">菜單二</a></li> <li><a href="/menu3/">菜單三</a></li> </ul> </div> <div class="menu"> 菜單三首頁 </div> </body> </html>
上面我的的需求雖然完成了但是有沒有什么沒問題?你會發現html重復代碼太多了,如果領導不瞎,最晚后天你就可以領盒飯了。
2. 母版繼承示例
所以針對與我上面的需求,很顯然你現在所擁有的知識點已經解決不了了。那么接下來就是本節的重點:模版繼承。根據這個知識點名字的特點,我們應該想到,我們可不可以建立一個父類,然后讓所有的子孫類都繼承我的父類,這樣我就可以節省很多代碼了,讓我的代碼非常的清新、簡單。這里的父類就不叫父類了他有一個專有名詞:母版。
接下來我們先創建一個母版。(最好不要將base頁面直接作為母版,母版就是只設置公用的部分,其他一概不要。)
<!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"> <title>Bootstrap 101 Template</title> <style> body{ margin: 0; padding: 0; } .nav{ background-color: black; color: #eaeaea; height: 30px; width: 100%; } .clearfix{ content: ''; display: block; clear: both; } .sidebar{ background-color: #b2b2b2; color: #435dff; width: 20%; height: 1000px; float: left; } .sidebar ul{ margin: 0; } .menu{ width: 80%; float: right; } </style> </head> <body> <div class="nav clearfix"> <a href="">普通洗浴</a> <a href="">盆兒堂</a> <a href="">局部護理</a> <a href="">關於我們</a> <a href="">預約電話</a> <input type="text">搜索 </div> <div class='sidebar'> <ul> <li><a href="/menu1/">菜單一</a></li> <li><a href="/menu2/">菜單二</a></li> <li><a href="/menu3/">菜單三</a></li> </ul> </div> <div class="menu"> </div> </body> </html>
接下來,我們將base menu1 menu2 menu3這四個頁面全部清空,然后在每個頁面的最上面加上這么一行代碼:
{% extends 'master_edition.html' %}
這個就實現了我要繼承母版master_edition.html。
3. 自定制效果
現在已經完成了繼承母版,這個只是減少了重復代碼,還沒有實現每個頁面自定制的一些內容,如果你想要實現自定制的內容怎么做?類似於模版系統你是不是應該在母版的具體位置做一個標識,然后在自己的頁面對應的地方進行自定制?那么這個類似於%占位符的特定的標識叫做鈎子。這幾個頁面只是在menu div不同,所以我們就在這里做一個鈎子就行了。
在母版的html對應的位置:
<div class="menu"> {% block content %} {% endblock %} </div>
block endblock就是對應的鈎子,content是此鈎子的名字。
然后在base menu1 menu2 menu3的頁面上(此時就以base頁面舉例):
{% block content %}
base頁面首頁
{% endblock %}
這樣你的代碼是不是非常的簡單了?
那么我們不僅可以在對應的html標簽設置鈎子,還可以在css、js設定對應的鈎子。所以母版繼承中一般設定鈎子的地方就是三部分: html、css、js。
以css舉例:
我們將base頁面的頂端導航條的背景顏色設置成紅色:
首先現在母版頁面對應的位置設置鈎子:
<style> body{ margin: 0; padding: 0; } .nav{ background-color: black; color: #eaeaea; height: 30px; width: 100%; } .clearfix{ content: ''; display: block; clear: both; } .sidebar{ background-color: #b2b2b2; color: #435dff; width: 20%; height: 1000px; float: left; } .sidebar ul{ margin: 0; } .menu{ width: 80%; float: right; } {% block nav %} {% endblock %} </style>
然后找到base頁面:
{% block nav %}
.nav{
background-color: red;
}
{% endblock %}
這樣你的base頁面的導航條就變成紅色啦!
js的母版繼承我們就不再這里嘗試了,自己私下可以嘗試一下。
4. 保留母版內容並添加新特性
還有一個情況我們也會遇到,就是我既要留住母版的內容,又要在自己的html添加一些新的標簽。這個我們在面向對象時是不是也遇到過?當時用什么方法既執行父類方法又可以執行子類方法?super!在這里我們也用super!
母版html:
<div class="menu"> {% block content %} <div>這是母版測試頁面</div> {% endblock %} </div>
base.html:
{% block content %}
{{ block.super }}
base頁面首頁
{% endblock %}
在鈎子里面加上{{ block.super }}即可。
5. 注意
-
如果你在模版中使用
{% 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
標簽。 - 結束一個鈎子時可以標注此鈎子的名字,比如 {% endblock content%}這樣就可以結束此鈎子不至於將其他的block鈎子一並結束。
六、組件
組件就是將一組常用的功能封裝起來,保存在單獨的html文件中,(如導航條,頁尾信息等)其他頁面需要此組功能時,按如下語法導入即可。 這個與繼承比較類似,但是‘格局’不同,繼承是需要寫一個大的母版,凡是繼承母版的一些html基本上用的都是母版頁面的布局,只有一部分是自己頁面單獨展現的,這好比多以及排布好的多個組件。
{% include 'xx.html' %}
比如我們寫一個nav導航條組件:
<!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"> <title>Bootstrap 101 Template</title> <style> body{ margin: 0; padding: 0; } .nav{ background-color: black; color: #eaeaea; height: 30px; width: 100%; } .clearfix{ content: ''; display: block; clear: both; } </style> </head> <body> <div class="nav clearfix"> <a href="">普通洗浴</a> <a href="">盆兒堂</a> <a href="">局部護理</a> <a href="">關於我們</a> <a href="">預約電話</a> <input type="text">搜索 </div> </body> </html>
然后我們在創建流程去使用我們的組件:
urls: url(r'^component/', views.component), views: def component(request): return render(request,'component.html') component頁面: <!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"> <title>Bootstrap 101 Template</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> {% include 'nav.html' %} <h1>你好,世界!</h1> <div>我是componet頁面</div> </body> </html>
組件和插件的區別:
組件是提供某一完整功能的模塊,如:編輯器組件,QQ空間提供的關注組件 等。
而插件更傾向封閉某一功能方法的函數。
這兩者的區別在 Javascript 里區別很小,組件這個名詞用得不多,一般統稱插件。
七 自定義標簽和過濾器
我們都學過了Django給我們提供的標簽和過濾器,但是這些不能滿足我們日常開發的所有需求,所以DJango為我們提供了一個很牛逼的功能就是我們可以自定義標簽和過濾器。接下來我們看看這個怎么玩。
1. 自定義過濾器
Django的模版系統給我們提供了很多過濾器,比如切割、全大寫、獲取元素個數,聯合join,安全性質的safe等等,這些都是對數據(尤其是字符串類型的數據)進行加工,但是這些都是模版系統提供給我們的,不能滿足應對工作中的所有需求,所以Django給我們提供了口子:讓我們可以自己定義過濾器,這樣我們開發起來更加的靈活。接下來我們講解如何自己定義過濾器。
1. 在應用的目錄下創建templatetags文件夾(文件夾必須這樣命名)。
2. 在templatetags文件下創建py文件(任意命名即可)。
我這里命名為network_language.py。
3. 在py文件中引入template模塊並創建注冊器。
from django import template register = template.Library()
4. 自定義過濾器函數。
下面講到的自定義標簽以及simple_tags,與前三步一模一樣,並且都是在本文件中操作。
@register.filter def adjoin(v1): pass # adjoin就是我們自定義的過濾器函數。 # 此函數必須被register.filter裝飾,這樣才能生效。 # 我們現在先不做任何功能,一會在定義功能。
完成上面這個四步,我們就算是自定義了一個過濾器函數。那么如何使用呢?模版系統自帶的過濾器如何使用?他是通過對render要渲染的變量加上管道符,然后在管道符后面加上具體的過濾器的名字,這樣就可以對變量進行簡單加工了。我們自定義的過濾器也是這樣用法。接下來我們重新設計一個url流程:
urls: url(r'^templatetag/', views.template_tag), views: def template_tag(request): name = '天琪' return render(request,'templatetag.html', {'name': name}) html: <!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"> <title>Bootstrap 101 Template</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> {% load network_language %} # 引入templatetags文件夾下面的network_language.py文件 {{ name|adjoin }} # name就是render渲染的變量,adjoin就是自定義的過濾器的函數名 </body> </html>
此時你自定義的過濾器里面的adjoin代碼:
from django import template register = template.Library() @register.filter def adjoin(v1): return v1 + '噢里給'
我們自定義的過濾器就是完成了簡單的功能:給name變量拼接了一個網絡用語:奧利給。那么整個他的執行流程是什么呢?
首先瀏覽器發送請求至url,url通過請求路徑找到對應的views視圖函數template_tag,然后執行到return時先不會給瀏覽器馬上返回html頁面,而是通過render進行模版渲染,當渲染到 {% load network_language %}這一行,render會自動找到templatetags文件夾下面的network_language文件,然后在向下讀取,執行自定義過濾器adjoin函數,並且將變量name對應的'天琪'傳遞給adjoin函數的形參v1,得到返回值'天琪噢里給'之后,替換{{ name|adjoin }},渲染完畢之后,將此html頁面返回給瀏覽器。
這個就是整體的過程。那么有人可能會問了,我自定義的過濾器函數只能設定一個形參么?不是的,自定的過濾器函數設定形式參數至多兩個。接下來我們演示一個兩個參數的。
# html: {% load network_language %} {{ name|_adjoin:'微笑的面對它' }} # templatetags/network_language.py: @register.filter def _adjoin(v1, v2): return v1 + v2 + '噢里給!'
第二個參數是通過過濾器的冒號后面傳遞的。
至此,我們自定義過濾器這部分就已經給大家講完了,可以練習一下~
2. 自定義標簽
我們學習完自定義過濾器之后,再來看看自定義標簽,自定義標簽與自定義過濾器差不多,前三個步驟是一樣,接下來就是定義自定義標簽函數不同:
views:我們還是使用template_tag函數,只是增加了一些變量。
def template_tag(request): name = '天琪' content = '我太難了' status = '在線學習' return render(request,'templatetag.html', locals())
html:
{% load network_language %} {% all_join name status content '不要怕'%}
network_language.py:
@register.simple_tag def all_join(v1, v2, v3, v4): return v1 + v2 + v3 + v4 + '噢里給!'
其實自定義標簽和自定義過濾器差不多,都是我們設計一些函數,增加一些自定制的功能,也有一些細微的區別,我們總結一下:
- 自定制過濾器至多只能接受兩個參數,而自定制標簽可以接受多個參數,這樣看來自定制標簽更加靈活。
- 自定制過濾器必須依賴於 變量,他的目的就是對變量進行加工{{ name|adjoin }} ;而自定制標簽可以不依賴於變量直接使用{% all_join %}.
- 自定制過濾器可以用在if、for等語句后,自定制標簽不可以。
{% if num|filter_multi:30 > 100 %} {{ num|filter_multi:30 }} {% endif %}
3.inclusion_tag
這個標簽不同於上面的兩種,這個標簽是將一段html代碼插入到我們html頁面中,有點兒類似於組件,但是比組件還靈活。上一節我們講組件時,我們將自己設計的一個頂端的導航條nav.html作為一個組件,然后讓另一個頁面去使用,還記得這個例子吧?這次我們用inclusion_tag去展示一下,對比分析一下這兩個有什么不同。
views:我們加了一個show_list變量
def template_tag(request): name = '天琪' content = '我太難了' status = '在線學習' show_list = ['課程分類', '在線學習', '解答疑問', '講師介紹', '網站介紹'] return render(request,'templatetag.html', locals())
teamplatetag.html: 我設計在network_language中自定制inclusion標簽函數,函數名為nav_data,然后將show_list傳遞進去。
{% load network_language %}
{% nav_data show_list %}
network_language.py:
@register.inclusion_tag('nav.html') def nav_data(argv): argv += [datetime.datetime.now()]return {'data': argv}
此時我在這個自定制函數中對show_list進行了加工,並且通過return(這里的return有點兒類似於render)將數據傳遞到nav.html頁面對應的位置。
nav.html:
<!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"> <title>Bootstrap 101 Template</title> <style> body{ margin: 0; padding: 0; } .nav{ background-color: black; color: #eaeaea; height: 30px; width: 100%; } .clearfix{ content: ''; display: block; clear: both; } </style> </head> <body> <div class="nav clearfix"> {% for foo in data %} <a href="">{{ foo }}</a> {% endfor %} <input type="text">搜索 </div> </body> </html>
然后將數據展示到導航條上面相應的位置上,最終的效果如下:
然后我們對比分析組件,組件是只能將html里面的一部分(導航條、左右側欄等)原封不動被引入到相應的其他html頁面中,而
inclusion_tag這個自定制標簽,不僅可以完成組件的功能,而且還可以操作被導入的html組件,使其更加靈活。
八、靜態文件
截止到目前為止,我們還沒有應用到css、js等文件,只是使用了html頁面,現在我們的頁面可算是不要太丑了。所以項目中我們肯定是要引入靜態文件的,什么是靜態文件?靜態文件就是我們之前學過的css、js、圖片文件、視頻文件等等,我們在html想要使用他們就是引用靜態文件,之前我們寫頁面是需要通過標簽引入靜態文件,並且需要各種路徑的配置,現在我們利用Django做一個簡單的配置就可以直接引入靜態文件了。
我們在重新創建一個項目static_pro:
url: url(r'^index/', views.index), views: def index(request): return render(request, 'index.html') html: <!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"> <title>Bootstrap 101 Template</title> <link href="" rel="stylesheet"> </head> <body> <h1>你好,世界!</h1> </body> </html>
我們的靜態文件不只是一個文件,這里面包含很多的文件,所以我們應該創建一個文件夾,將所有的靜態文件都放置在此目錄中,所以,我們在整個項目的目錄下創建一個專門放置靜態文件的文件夾:我們取名'jingtaiwenjian'(為了教學使用,工作中決不允許出現拼音形式),然后我們在此靜態文件里面創建一個css1.css文件,專門放置css代碼。
接下來我們如何引用我們的css1靜態文件呢?按照我們之前的操作,在html頁面的link標簽中引入此文件的相對路徑,是行不通的。
引入靜態文件方式一
我們在Django框架中,就遵循Django規范,那么Django是如何配置css。
1. 在settings配置文件中,配置靜態文件路徑
STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'jingtaiwenjian'), ]
# STATICFILES_DIRS 此常量名設置可以任意構建,一般約定俗成都是這樣命名的。
2. 在index.html文件中,引入css文件
<link href="/static/css1.css" rel="stylesheet">
注意:這里面的路徑如果你寫的是/jingtaiwenjian/css1.css,這樣css文件是引用不到的,你要像我上面寫的一樣。那么為什么呢?這個'static'是什么東西?接下來跟你簡單聊聊這個static。
別名static
這個static是給靜態文件(比我們的項目的靜態文件的名字為:jingtaiwenjian)起的別名,他在哪里可以配置呢?在我們settings里面就可以配置:
Django默認給靜態文件起了別名,當然你也可以自己設定別名,比如:
STATIC_URL = '/olddriver/'
如果你要是更改這個別名,你在index.html中的引用就需要更改,所以一般我們不去更改別名:
這樣也可以成功訪問,那么Django為什么要給靜態文件起別名呢?這樣有什么好處呢?
1. 使用別名代替真實的靜態文件名字,防止有人對你的靜態文件發起惡意攻擊,保證靜態文件的安全。
因為請求一個web網站時,都會對css、js發起請求,並且這些請求都是可以訪問到的url:
我們訪問一下這個URL:
再比如我們打開京東,看一下京東的網絡請求:
通過這個網址我們可以拿到他的css代碼:
這種css代碼是壓縮混淆處理的,有些內容你是看不懂的,就相當於加密了,但是我們可以獲取到。雖然可以讓你獲取到,但是由於你的static是別名,他是不能對你的靜態文件發起攻擊的。
2. 使用別名代替真實的靜態文件名字,保持了代碼的拓展性。
如果以后遇到了需求,必須將靜態文件的名字改掉(比如我們本次取的名字jingtaiwenjian就不規范),如果沒有別名的話,你必須將所有的引用靜態文件的相關link路徑都必須改掉,這樣太麻煩了,但是我們有了別名的概念,無論你以后如何更改靜態文件的名字,都不會造成影響的。
我將靜態文件名字改成了staticfile,當我再次訪問index頁面時,依然還是可以訪問的。
請求路徑還是別名作為路徑。
所以,針對於上述情況,起別名還是又好處的。
引入靜態文件方式二
我們還可以通過第二種方式引入靜態文件,第一種方式是有漏洞的,假如我們已經完成了一期項目,你的項目中已經創建了多個html文件,並且都一直通過第一種方式引入靜態文件,此時你跳槽了,其他的人接收你的項目,他沒有注意到你的別名為static,而當它二期項目已經進展了很長時間發現你的static別名與二期項目中的某些url沖突了,這時必須要更改你的別名才可以解決問題,那么怎么做?因為你通過第一種方式引入的靜態文件,如果你把別名改了,你的很多html頁面的link路徑都必須要更改,所以這種方式還是有弊端的。那么接下來我介紹第二種引入靜態文件的方式,就可以完美避開這個問題。
settings:
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'staticfile'), ]
index.html:
{% load static %} <!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"> <title>Bootstrap 101 Template</title> <link href="{% static 'css1.css' %}" rel="stylesheet"> </head> <body> <h1>你好,世界!</h1> </body> </html>
通過這種方式引入靜態文件,無論你更改別名,都沒有影響,因為他是根據settings你配置的靜態文件的路徑找到你的靜態文件的,不依賴於別名,所以這種方式也是我比較喜歡的一種方式。
了解:如果某個靜態文件路徑過長(比如一個圖片)並且此圖片多次被用到,我們每次引用這個圖片寫路徑很麻煩時,這樣可以給這個圖片路徑起個別名,以后在引用起來就簡單了:
{% load static %} {% static 'css1.css' as c %} <!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"> <title>Bootstrap 101 Template</title> <link href="{% static 'css1.css' %}" rel="stylesheet"> <link href="{{ c }}" rel="stylesheet"> </head> <body> <h1>你好,世界!</h1> </body>
引入靜態文件方式三
我們也可以通過 {% get_static_prefix %}方式引入靜態文件,這樣你的文件分隔符可以省略不寫了。
{% load static %} <!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"> <title>Bootstrap 101 Template</title> <link href="{% get_static_prefix %}css1.css" rel="stylesheet"> </head> <body> <h1>你好,世界!</h1> </body> </html>
了解:如果某個靜態文件路徑過長(比如一個圖片)並且此圖片多次被用到,我們每次引用這個圖片寫路徑很麻煩時,這樣可以給這個圖片路徑起個別名,以后在引用起來就簡單了:
{% load static %} {% get_static_prefix as c %} <!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"> <title>Bootstrap 101 Template</title> {# <link href="{% static 'css1.css' %}" rel="stylesheet">#} {# <link href="{{ c }}" rel="stylesheet">#} <link href="{{ c }}css1.css" rel="stylesheet"> </head> <body> <h1>你好,世界!</h1> </body> </html>