1. 程式人生 > 實用技巧 >Django模板渲染

Django模板渲染

django模板渲染

模板渲染,模板指的就是html檔案,渲染指的就是字串替換,將模板中的特殊符號替換成相關資料

基本語法

{{ 變數 }}
{% 邏輯 %}

變數使用

看示例

Views.py檔案

def home(request):
    class A:
        def __init__(self):
            self.username = 'bob'
        #如果方法需要在模板中使用,那麼不能有其他引數
        def xx(self):  
            
            return 'bobxx'

    info 
= { 'name': 'jack', 'hobby': ['running', 'walking', 'reading'], 'num': 100, 'd1':{'aa':'bb'}, 'l1':[11,22,{'cc':'dd'}], 'a': A(), } return render(request, 'home.html', info)

home.html內容如下

重點:萬能的據點號。通過點可以進行資料的索引取值,屬性取值,取方法等等

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>{{ name }}</h2> <ul> {% for i in hobby %} <li>{{ i }}</li> {% endfor %} </ul> <hr> {{ num }} <p> {{ l1.2.ss }}
</p> <p> {{ d1.xx }} </p> <p> {{ a.username }} </p> <p> {{ a.xx }} <!-- 方法不能加括號,意味著不能穿引數,也就是說你後面定義的方法,不能有引數 --> </p> </body> </html>

urls.py內容

url(r'^home/', views.home),

過濾器

在Django的模板語言中,通過使用 過濾器 來改變變數的顯示。

過濾器的語法:{{ value|filter_name:引數 }}

使用過濾器的注意事項

1. 過濾器支援“鏈式”操作。即一個過濾器的輸出作為另一個過濾器的輸入。

2. {{ sss|過濾器1:30|過濾器2.... }}

3. 過濾器可以接受引數,例如:{{ sss|truncatewords:30 }},這將顯示sss的前30個詞。

4. '|'左右沒有空格

內建過濾器

常用的內建過濾器示例

(1) default

如果一個變數是false或者為空,使用給定的預設值。 否則,使用變數的值。

{{ value|default:"nothing"}}

如果value沒有傳值或者值為空或者為False的話就顯示nothing

(2) length

返回值的長度,作用於字串和列表。

{{ value|length }}

返回value的長度,如 value=['a', 'b', 'c', 'd']的話,就顯示4.

(3) filesizeformat

將值格式化為一個 “人類可讀的” 檔案尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:

{{ value|filesizeformat }}

如果 value 是 123456789,輸出將會是 117.7 MB。

(4) slice

切片,如果 value="hello world",還有其他可切片的資料型別

{{value|slice:"2:-1"}}
(5) date

格式化,如果 value=datetime.datetime.now(),如果不想顯示為UTC時間,將django的settings.py配置檔案中的TIME_ZONE這一項修改一下,修改為TIME_ZONE = 'Asia/Shanghai'

比如,後臺返回的資料為{'value':datetime.datetime.now()}

對上面的資料進行格式化:{{ value|date:"Y-m-d H:i:s"}}

 關於時間日期的可用的引數(除了Y,m,d等等)還有很多,有興趣的可以去查檢視看。

(6) safe

xxs攻擊,全稱跨站指令碼攻擊    Django的模板中在進行模板渲染的時候會對HTML標籤和JS等語法標籤進行自動轉義,原因顯而易見,這樣是為了安全,django擔心這是使用者新增的資料,比如如果有人給你評論的時候寫了一段js程式碼,這個評論一提交,js程式碼就執行啦,這樣你是不是可以搞一些壞事兒了,寫個彈窗的死迴圈,那瀏覽器還能用嗎,是不是會一直彈窗啊,這叫做xss攻擊,所以瀏覽器不讓你這麼搞,給你轉義了。但是有的時候我們可能不希望這些HTML元素被轉義,比如我們做一個內容管理系統,後臺新增的文章中是經過修飾的,這些修飾可能是通過一個類似於FCKeditor編輯加註了HTML修飾符的文字,如果自動轉義的話顯示的就是保護HTML標籤的原始檔。為了在Django中關閉HTML的自動轉義有兩種方式,如果是一個單獨的變數我們可以通過過濾器“|safe”的方式告訴Django這段程式碼是安全的不必轉義。

{'a_tag':'<a href="">百度</a>',}

渲染
<p>
    {{ a_tag|safe }} #生成標籤效果
</p>
(7) truncatechars

如果字串字元多於指定的字元數量,那麼會被截斷。截斷的字串將以可翻譯的省略號序列(“...”)結尾。

引數:截斷的字元數

{{ value|truncatechars:9}} #注意:最後那三個省略號也是9個字元裡面的,也就是這個9截斷出來的是6個字元+3個省略號,有人會說,怎麼展開啊,配合前端的點選事件就行啦
(8) truncatewords

在一定數量的字後截斷字串,是截多少個單詞。

例如:‘are you ok’,

{{ value|truncatewords:2}} #上面例子得到的結果是 'are you...'

(9) cut

移除value中所有的與給出的變數相同的字串

{{ value|cut:' ' }}

如果value為'i love you',那麼將輸出'iloveyou'.

(10) join

使用字串連線列表,{{ list|join:', ' }},就像Python的str.join(list)

<p>{{ hobby|join:'+' }}</p>

注意:模版渲染在瀏覽器渲染之前,模板渲染就是字串替換,替換完成之後,將替換完的整體檔案字串返回給瀏覽器,瀏覽器再進行瀏覽器渲染,展示頁面效果

標籤

語法{% 標籤 %}

(1) for迴圈標籤

示例:

#迴圈列表
<ul>
    {% for xx in hobby %}
    <li>{{ xx }}</li>
    {% empty %}  #當hobby為空或者後臺沒有給這個資料,那麼會顯示empty下面的內容
        <h2>抱歉,沒有查詢到相關資料</h2>
    {% endfor %}
</ul>

#迴圈字典
<ul>
    {% for k,v in d1.items %}  <!-- 直接迴圈字典資料,那麼是迴圈字典的key,迴圈d1.values,那麼表示迴圈字典的值, 迴圈d1.items,那麼k,v表示鍵和值-->
        <li>{{ k }}--{{ v }}</li>
    {% endfor %}

</ul>

#迴圈計數
<ul>
{% for i in l1 %}

{#    {{ forloop }}#}
    {% for h in hobby %}
        <li>{{ forloop.parentloop.counter }}--{{ forloop.revcounter0 }}---{{ h }}--{{ forloop.last }}</li>
    {% endfor %}

{% endfor %}
</ul>

forloop的解釋
 注:迴圈序號可以通過{{forloop}}顯示,必須在迴圈內部用 
forloop.counter            當前迴圈的索引值(從1開始),forloop是迴圈器,通過點來使用功能
forloop.counter0           當前迴圈的索引值(從0開始)
forloop.revcounter         當前迴圈的倒序索引值(從1開始)
forloop.revcounter0        當前迴圈的倒序索引值(從0開始)
forloop.first              當前迴圈是不是第一次迴圈(布林值)
forloop.last               當前迴圈是不是最後一次迴圈(布林值)
forloop.parentloop         本層迴圈的外層迴圈的物件,再通過上面的幾個屬性來顯示外層迴圈的計數等
  
#反向迴圈
可以利用{% for obj in list reversed %}反向完成迴圈。
示例:
<ul>
    {% for xx in hobby reversed %}
    <li>{{ xx }}</li>
    {% endfor %}
</ul>

(2) if 標籤

{% if %}會對一個變數求值,如果它的值是“True”(存在、不為空、且不是boolean型別的false值),對應的內容塊會輸出。

{% if num > 100 or num < 0 %}
    <p>無效</p>  <!--不滿足條件,不會生成這個標籤-->
{% elif num > 80 and num < 100 %}
    <p>優秀</p>
{% else %}  <!--也是在if標籤結構裡面的-->
    <p>湊活吧</p>
{% endif %}

當然也可以只有if和else

{% if user_list|length > 5 %}  <!--結合過濾器來使用-->
  七座豪華SUV
{% else %}
    黃包車
{% endif %}

if語句支援 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷,注意條件兩邊都有空格。

(3) with標籤

使用一個簡單地名字快取一個複雜的變數,多用於給一個複雜的變數起別名,當你需要使用一個“昂貴的”方法(比如訪問資料庫)很多次的時候是非常有用的

例如:

注意等號左右不要加空格。

{% with total=business.employees.count %}
    {{ total }} <!--只能在with語句體內用-->
{% endwith %}

{% with business.employees.count as total %}
    {{ total }}
{% endwith %}

使用標籤的注意事項

1. Django的模板語言不支援連續判斷,即不支援以下寫法:

{% if a > b > c %}
...
{% endif %}

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的值。

自定義標籤和過濾器

自定義過濾器

注意:在settings中的INSTALLED_APPS配置當前app,不然django無法找到自定義的simple_tag.

1、在app中建立templatetags資料夾(資料夾名只能是templatetags)

2、在templatetags資料夾中建立任意 .py 檔案,如:mytag.py

3、在mytag.py檔案中寫上如下內容

from django import template

register = template.Library() #製作註冊器,名字必須叫register

#過濾最多兩個引數
@register.filter #註冊過濾器,需要兩個引數的
def add(v1, v2):  #v1表示管道符前面的,v2表示冒號後面的引數
    print(v1,v2) #100 50
    return v1 + v2

@register.filter #註冊過濾器,需要一個引數的
def xxx(v1):  #v1表示管道符前面的
    print(v1) 
    return 'xxx'

4、使用,在html檔案中寫上如下內容

{% load mytag %}  <!-- 首先通過load來載入一下mytag檔案,不一定放在檔案的開頭,但是一定要放在使用過濾器的前面先進行引用 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<h1>base頁面</h1>
  <!--{% load mytag %} 放這裡也是可以的-->  
<div>
    {{ num|add:50}}  <!-- 使用過濾器,和django內建過濾器用法一樣,這裡生成的是add函式的返回值 -->
</div>
<div>
    {{ num|xxx }}
</div>
<!--{% load mytag %} 放這裡不行-->  

</body>

</html>

自定義標籤

過程:

1、在app中建立templatetags資料夾(資料夾名只能是templatetags)

2、在templatetags資料夾中建立任意 .py 檔案,如:mytag.py

3、在mytag.py檔案中寫上如下內容

from django import template

register = template.Library() #製作註冊器,名字必須叫register

@register.simple_tag
def atag(v1,v2): #沒有引數個數限制
    print(v1,v2)
    return v1 + v2

4、使用,在html檔案中寫上如下內容

{#{% load mytag %}#}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<h1>base頁面</h1>
{% load mytag %}

<div>
    {% atag 'a' 'b' %}  <!-- 注意,是{%%} 來包裹使用,先是標籤名稱然後空格寫引數,引數之間也是空格分隔的 -->
</div>

</body>

</html>

模板繼承

將一些頁面公共的部分,可以抽離出來單獨做成一個html頁面,使用這些公用部分的其他html檔案,只需要繼承一下它就可以了,具體使用流程如下:

1 建立公用模板,比如內容如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body{
            padding: 0;
            margin: 0;
        }
        {% block css %}
        .nav{
            height: 60px;
            background-color: green;
        }
        {% endblock %}
        .nav a{
            color:white;
            text-decoration: none;
        }
        .left-menu{
            width: 30%;
            background-color: rgba(0,0,0,0.5);
            float:left;
        }
        .menu .menu-title{
            text-align: center;
        }
        .main{
            float: right;
            width: 65%;
            height: 300px;
            border: 1px solid red;
        }
    </style>
</head>
<body>

<div class="nav">
    <a href="/xx1/">首頁</a>
    <a href="/person/">個人中心</a>
    <a href="/detail/">詳情頁</a>
</div>
<div class="left-menu">
    <div class="menu">
        <div class="menu-title">選單1</div>
        <div class="menu-body">
            <div class="item">包子</div>
            <div class="item">饅頭</div>
            <div class="item">涼皮</div>
            <div class="item">麵條</div>
        </div>
        <div class="menu-title">選單2</div>
        <div class="menu-body">
            <div class="item">排骨藕湯</div>
            <div class="item">粉蒸肉</div>
            <div class="item">臘魚塊</div>
            <div class="item">灌腸</div>
        </div>
    </div>
</div>
<div class="main">
    {% block content %}
    公共頁面
    {% endblock %}
</div>

</body>
{% block js %}
    
{% endblock %}

</html>

2 將來如果說繼承公用模板的html檔案中需要修改公用模板中的一些內容,那麼需要在公用模板中預留一些鉤子,鉤子的寫法如下

{% block content %}  #block 後面的塊名稱隨便起
公共頁面
{% endblock %}
#也可以這樣寫 {% endblock content %}  #endblock指定名稱

3 繼承公用模板需要在html檔案中寫如下內容:

{% extends 'xx.html' %}  <!-- 需要先繼承一下公用模板,寫法就是extends '公用模板檔名稱',注意,必須寫在第一行 -->

{% block css %}
.nav{
    height: 60px;
    background-color: pink;
}
{% endblock %}

{% block content %}
    <h1>首頁</h1>
{% endblock %}

4 在使用公用模板的其他html檔案中,如果需要更改公用模板裡面的內容,只需要在html檔案中寫上相同的鉤子,鉤子裡面寫上自定義的內容,寫法如下

{% block css %}
.nav{
    height: 60px;
    background-color: pink;
}
{% endblock %}

{% block content %}
    <h1>首頁</h1>
{% endblock %}

注意事項:

  • 如果你在模版中使用 {% extends %} 標籤,它必須是模版中的第一個標籤。其他的任何情況下,模版繼承都將無法工作,模板渲染的時候django都不知道你在幹啥。

  • 在base模版中設定越多的 {% block %} 標籤越好。請記住,子模版不必定義全部父模版中的blocks,所以,你可以在大多數blocks中填充合理的預設內容,然後,只定義你需要的那一個。多一點鉤子總比少一點好。

  • 如果你發現你自己在大量的模版中複製內容,那可能意味著你應該把內容移動到父模版中的一個 {% block %} 中。

  • {{ block super }}的使用,在子模板中也展示出父模板原來鉤子中的內容

{% block content %}

    <h1>首頁</h1>
    {{ block.super }}
{% endblock %}

為了更好的可讀性,你也可以給你的 {% endblock %} 標籤一個 名字 。例如:

{% block content %}
...
{% endblock content %}  

在大型模版中,這個方法幫你清楚的看到哪一個  {% block %} 標籤被關閉了。

不能在一個模版中定義多個相同名字的 block 標籤。

#兩個block都叫content,這種寫法是不對的
{% block content %}

    <h1>首頁</h1>
    {{ block.super }}
{% endblock %}
{% block content %}

    <h1>首頁</h1>
    {{ block.super }}
{% endblock %}