一、模板介紹
Django的模板 = HTML代碼 + 模板語法
存放在templates目錄下的HTML文件就稱為模板文件,如果我們想要返回 的HTML文件中的數據是動態的,那么就必須在HTML文件中嵌入變量,這就會用到Django的模板語法。
二、變量
在Django的模板語言中的變量語法:
View:{ ' HTML變量名 ' : ‘ views變量名 ’ }
HTML:{{ 變量名 }}
views.py 文件
from django.shortcuts import render
import time
def index(request):
times = time.time()
name = '小楊'
name_list = ['小楊', '艾倫', '鮑勃']
info_dict = {'name': '小楊', 'age': 18, 'job': '攻城獅'}
class A:
def __init__(self, hobby):
self.hobby = hobby
def func(self):
return self.hobby
# 也可以傳入對象
Bob = A('攻城獅')
# 將數據傳遞給 index.html 文件進行渲染在發送給瀏覽器
return render(request, 'index.html', {'times': times, 'Bob': Bob, 'name': name, 'name_list': name_list, 'info_dict': info_dict})
index.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 接收數據進行渲染 -->
<p>{{ times }}</p>
<p>{{ name }}</p>
<p>{{ name_list.2 }}</p> <!-- 取列表中索引為2的數據 -->
<p>{{ info_dict.age }}</p> <!-- 取字典中鍵值為age的數據 -->
<p>{{ Bob.func }}</p> <!-- 執行對象中的方法返回數據 -->
</body>
</html>
三、過濾器
過濾器類似於python的內置函數,用來把視圖傳入的變量加以修飾后在顯示
過濾器的語法:{{ 變量名|過濾器 : 可選參數 }}
注意事項:
- 過濾器支持“ 鏈式 ” 操作 。
- 過濾器參數包含空格需要用引號包裹起來。
- '|' 左右沒有空格
常用過濾器
default
如果一個變量是false或者是空,就使用給定的默認值。否則,使用變量的值。
{{ value|default:"默認值" }}
length
返回值的長度,主要用於字符串和列表。
{{ value|length }}
filesizeformat
將值的格式轉換為一個可讀的,主要用於顯示文件大小
如果 value 是 123456789,輸出將會是 117.7 MB。
{{ value|filesizeformat }}
slice
切片
{{ value|slice:"2:4" }}
date
格式化,若value = datetime.datetime.now()
{{ value|date:"Y-m-d H:i:s" }}
safe
轉義,若value是一串代碼,就可以對其進行轉義成非代碼的,防止xss攻擊。
{{ value|safe }}
truncatechars
如果字符串的字符個數多於指定的字符數量,那么就會被截斷。截斷的字符串將以可翻譯的序號(...)結尾
{{ value|truncatechars:'6' }} # 后面的三個省略號也算在6個字符里面
truncatewords
在一定數量的字后截斷字符串,是截多少個單詞。
{{ value|truncatewords:2 }}
cut
移除value中所有的與給出的變量相同的字符串
{{ value|cut:'移除的字符' }}
join
使用字符串連接列表。
{{ list|join:', ' }}
四、標簽Tags
標簽是為了在模板中完成一些特殊功能,語法為{% 標簽名 %},一些標簽還需要搭配結束標簽 {% endtag %}
for 標簽
1、遍歷每一個元素
{% for food in foods_list %}
<p>{{ food }}</p>
{% endfor %}
2、可以利用{% for obj in list reversed %}反向循環。
{% for food in foods_list reversed %}
<p>{{ food }}</p>
{% endfor %}
3、遍歷一個字典
{% for k, v in f_dict.items %}
<p>{{ k }}:{{ v }}</p>
{% endfor %}
for ... empty
可選的{ % empty % } 從句,給出的組是空的或者沒有被找到時,執行的操作
{% for food in foods_list %}
<p>{{ food }}</p>
{% empty %}
<p>沒有foods_list,或者foods_list為空</p>
{% endfor %}
for循環的其他方法
forloop.counter 當前循環的索引值(從1開始),forloop是循環器,通過點來使用功能
forloop.counter0 當前循環的索引值(從0開始)
forloop.revcounter 當前循環的倒序索引值(從1開始)
forloop.revcounter0 當前循環的倒序索引值(從0開始)
forloop.first 當前循環是不是第一次循環(布爾值)
forloop.last 當前循環是不是最后一次循環(布爾值)
forloop.parentloop 本層循環的外層循環的對象,再通過上面的幾個屬性來顯示外層循環的計數等
forloop.parentloop.counter
if 標簽
對一個變量求值,如果它的值是“True” (存在,不為空,且不是boolean類型的False值),對應的內容塊會輸出。
if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷,注意條件兩邊都有空格。
{% if num > 100 or num < 0 %}
<p>條件1滿足</p> <!--不滿足條件,不會生成這個標簽-->
{% elif num > 80 and num < 100 %}
<p>條件1不滿足,條件2滿足</p>
{% else %} <!--也是在if標簽結構里面的-->
<p>條件都不成立,執行我吧</p>
{% endif %}
with 標簽
給一個復雜的變量起別名
{% with total=business.employees.count %}
{{ total }} <!--只能在with語句體內用-->
{% endwith %}
或者
{% with business.employees.count as total %}
{{ total }}
{% endwith %}
csrf_token 標簽
用於跨站請求偽造保護
在form表單里面任何位置寫上。
工作原理:
1、在GET請求到form表單時,標簽{% csrf_token%}會被渲染成一個隱藏的input標簽,該標簽包含了由服務端生成的一串隨機字符串,如下:
<input type="hidden" name="csrfmiddlewaretoken" value="dmFo...O5">
2、在使用form表單提交POST請求時,會提交上述隨機字符串,服務端在接收到該POST請求時會對比該隨機字符串,對比成功則處理該POST請求,否則拒絕,以此來確定客戶端的身份
實例:
<form action="" method="post">
{% csrf_token %}
用戶名:<input type="text">
密碼:<input type="password">
<input type="submit">
</form>
五、自定義過濾器和標簽
當內置的過濾器和標簽無法支持我們的需求時,就使用自定義標簽或過濾器
自定義過濾器
步驟:
1、在文件夾app01中創建子文件夾 templatetags (文件夾只能是templatetags)
2、在 templatetags 新建任意 .py 文件,如 mytags.py,在該文件中自定義過濾器或標簽。
內容如下
# mytags.py 文件
from django import template # 導入的模塊
register = template.Library() # register 固定的名字 注冊器
# 自定義過濾器
@register.filter
def my_filter1(v1): # 不帶參數的
# 對 v1 的操作
v = v1 + '操作'
return v
"""
使用:HTML文件中
{% load 文件名 %} --> 在HTML文檔中必須先加載存有自定義過濾器和標簽的文件
{{ value1|my_filter1 }} --> 無參數
把 value1 的值傳入給 v1 ,做處理后返回。
"""
@register.filter
def my_filter2(v1, v2): # 帶參數的過濾器(最多只能帶兩個)
# 對 v1 v2 的操作
v = v1 + v2
return v
"""
使用:HTML文件中
{% load 文件名 %} --> 在HTML文檔中必須先加載存有自定義過濾器和標簽的文件
{{ value1|my_filter1:value2 }} --> 有參數
把 value1 的值傳給 v1 ,參數 value2 傳給 v2 ,做處理后返回
"""
自定義標簽
步驟和自定義過濾器一樣:
# mytags.py 文件
from django import template # 導入的模塊
register = template.Library() # register 固定的名字 注冊器
@register.simple_tag
def my_tag(v1, v2, v3): # 自定義的標簽可以定義多個參數
# 對傳入的參數處理
v = v1 + v2 + v3
return v
"""使用:HTML文件中
{% load 文件名 %} --> 在HTML文檔中必須先加載存有自定義過濾器和標簽的文件
{% my_tag value1 value2 value3 %}
把 value1=v1 value2=v2 value3=v3 傳入標簽中,處理后返回。
"""
六、模板繼承
在Django模版引擎中最強大也是最復雜的部分就是模版繼承了。模版繼承可以讓您創建一個基本的 “骨架” 模版,它包含您站點中的全部元素,並且可以定義能夠被子模版覆蓋的 blocks 。
模板主要圍繞三種標簽的使用:include標簽、extends標簽、block標簽。
模板繼承之include標簽
include標簽也稱為組件
組件和插件的簡單區別:
- 組件是提供某一完整功能的模塊。
- 而插件更傾向於封閉某一功能方法的函數。
作用:在一個HTML模板文件中,引入或者重復使用另一個模板文件的內容。
{% include '模板名稱' %}
實例:
把整個 test.html 模板引入到 index.html 模板中
<!-- test.html 文件 -->
<div>
<ul>
<li>小楊</li>
<li>小明</li>
<li>鮑勃</li>
<li>艾倫</li>
</ul>
</div>
<!------------------------------------------------------------------------>
<!-- index.html 文件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
{% include 'test.html' %} <!-- 此處,當此文件發送給客戶端的時候,就變成了test.html文件的內容了 -->
</div>
</body>
</html>
模板繼承之extends標簽、block標簽
作用:在一個HTML模板文件中,引入或者重復使用另一個模板文件的內容。
include 有的功能 extends 全都有,但是 extends 可以搭配一個block標簽,用於在繼承的基礎上增加新的內容
模板制定鈎子
{% block 鈎子名 %}
<!-- 另一HTML模板引入此模板時可以從此處填充自己的內容 -->
{% endblock 鈎子名 %}
新模板引入舊模板,並從舊模板鈎子處填充新內容
{% extends '模板名' %}
<!-- 用新內容完全覆蓋了父模板鈎子中的內容 -->
{% block 鈎子名 %}
<p> Hello World... </p>
{% endblock 鈎子名 %}
實例:
1、制定一個模板 base.html ,它定義了一個頁面上面的導航欄,和頁面左邊的菜單欄,網頁中間由我們引入模板時自行填充自己的內容。
|---------------------|
| 導航欄 |
|-------|-------------|
| 菜 | |
| 單 | 自行填充的內容 |
| 欄 | |
|-------|-------------|
模板 base.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.top {
height: 100px;
background-color: red;
}
.left {
height: 400px;
width: 20%;
background-color: aqua;
float: left;
}
.centre {
float: right;
height: 400px;
width: 80%;
background-color: green;
}
</style>
</head>
<body>
<div class="top">
<a href="">導航一</a>
<a href="">導航二</a>
<a href="">導航三</a>
<a href="">導航四</a>
</div>
<div class="counter">
<div class="left">
<p><a href="">菜單一</a></p>
<p><a href="">菜單二</a></p>
<p><a href="">菜單三</a></p>
<p><a href="">菜單四</a></p>
</div>
<div class="centre">
{% block centent %}
<ul>
<li>信息1</li>
<li>信息2</li>
<li>信息3</li>
</ul>
<!-- 另一HTML模板引入此模板時可以從此處填充自己的內容 -->
{% endblock centent %}
</div>
</div>
</body>
</html>
2、index.html 模板引入base.html 模板,並在 base.html 模板鈎子處添加新內容。
{% extends 'base.html' %}
{% block centent %}
{{ block.super }} ————> 該變量會將父模板中 centent 中原來的內容繼承過來
<!--在繼承父模板內容的基礎上新增的標簽-->
<form action="" method="post">
{% csrf_token %}
用戶名:<input type="text">
密碼:<input type="password">
<input type="submit">
</form>
{% endblock centent %}
3、當啟動 Django 訪問 index.html 頁面時返回的內容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.top {
height: 100px;
background-color: red;
}
.left {
height: 400px;
width: 20%;
background-color: aqua;
float: left;
}
.centre {
float: right;
height: 400px;
width: 80%;
background-color: green;
}
</style>
</head>
<body>
<div class="top">
<a href="">導航一</a>
<a href="">導航二</a>
<a href="">導航三</a>
<a href="">導航四</a>
</div>
<div class="counter">
<div class="left">
<p><a href="">菜單一</a></p>
<p><a href="">菜單二</a></p>
<p><a href="">菜單三</a></p>
<p><a href="">菜單四</a></p>
</div>
<div class="centre">
<!-- 此處被替換 -->
<form action="" method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="WE..DF">
用戶名:<input type="text">
密碼:<input type="password">
<input type="submit">
</form>
</div>
</div>
</body>
</html>
總結:
- 標簽extends必須放在首行,base.html 中 block 越多控制性越強
- include 僅僅只是完全引用了其他模板文件,而 extends 卻可以搭配 block 在引用的基礎上進行擴寫
- 變量 {{ block.super }} 可以重用父類的內容,然后再父類基礎上增加新內容,而不是完全覆蓋
- 在一個模板中不能出現重名的block標簽。
七、靜態文件配置
在網站中我們需要用到大量的css、js、圖片等,這些都叫做靜態文件。
關於Django中靜態文件的配置,我們就需要在 settings 配置文件里面寫上這樣的內容:
1、例如在項目中創建一個 static_file 文件夾來存放靜態文件。
注意:別名可以隨便寫名字,但是如果改了名字,別忘了如果前端頁面如果是通過 /別名/靜態文件 調用靜態文件的話,前端頁面的靜態文件也要更改成一樣的
STATIC_URL = '/static/' # 別名
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static_file')
]
2、前端頁面引入靜態文件
方式一:不推薦,別名如果有變化,所有應用別名的地方都需要改
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/css/my.css">
</head>
<body>
<h1 class="c1" id="d1">點我就彈窗</h1>
<img src="/static/img/my.png" alt="">
<script src="/static/js/my.js"></script>
</body>
</html>
方式二:推薦,通過 load static 來找到別名,通過別名映射路徑的方式來獲取靜態文件
標簽static會接收傳入的參數,然后這根據settings.py中變量STATIC_URL的值拼接出一個完整的路徑
{% load static %} <!-- 注意:必須先加載文件static.py -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 注意:此處的static是一個定義在 static.py 中的一個標簽,名字與文件名一樣 -->
<link rel="stylesheet" href="{% static 'css/my.css' %}">
</head>
<body>
<h1 class="c1" id="d1">點我就彈窗</h1>
<img src="{% static 'img/my.png' %}" alt="">
<script src="{% static 'js/my.js' %}"></script>
</body>
</html>
方式三:get_static_prefix 標簽
和上面的效果一樣,不過只是用法不同。get_static_prefix 不能傳參,只能拼接,如下:
{% load static %} <!-- 注意:必須先加載文件static.py -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% get_static_prefix %}css/my.css">
</head>
<body>
<h1 class="c1" id="d1">點我就彈窗</h1>
<img src="{% get_static_prefix %}img/my.png" alt="">
<script src="{% get_static_prefix %}js/my.js"></script>
</body>
</html>
