Django模板層

先生發表於2021-06-09

一、模板介紹

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的內建函式,用來把檢視傳入的變數加以修飾後在顯示

過濾器的語法:{{ 變數名|過濾器 : 可選引數 }}

注意事項:

  1. 過濾器支援“ 鏈式 ” 操作 。
  2. 過濾器引數包含空格需要用引號包裹起來。
  3. '|' 左右沒有空格

常用過濾器

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標籤也稱為元件

元件和外掛的簡單區別:

  1. 元件是提供某一完整功能的模組。
  2. 而外掛更傾向於封閉某一功能方法的函式。

作用:在一個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>

總結:

  1. 標籤extends必須放在首行,base.html 中 block 越多控制性越強
  2. include 僅僅只是完全引用了其他模板檔案,而 extends 卻可以搭配 block 在引用的基礎上進行擴寫
  3. 變數 {{ block.super }} 可以重用父類的內容,然後再父類基礎上增加新內容,而不是完全覆蓋
  4. 在一個模板中不能出現重名的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>

相關文章