1. 程式人生 > >Django - 模板層 - 變數、過濾器、標籤

Django - 模板層 - 變數、過濾器、標籤

目錄

一、模板概念

二、 模板語法 - 變數 : {{ 變數 }}

1、直接呼叫輸出 - 相當於print

2、深度取值 - 獲取物件內部值

三、模板語法 - 過濾器 :{{ 位置引數1 | 過濾器函式 : 位置引數2}}

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

2- length : 返回值的長度。它對字串和列表都起作用

3- filesizeformat :將值格式化為一個可讀性高的檔案尺寸 

4- date :格式化日期

5- slice:切片操作

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

7- safe :是否轉義輸入框內的html、js元素等(使用-轉義;不使用-不轉義)

8- 其他過濾器

四、模板語法 - 標籤 : {% tag %} …… {% endtag%}

1- for標籤:迴圈結構

1-1 檢視迴圈資訊:{{ forloop }}

1-2 for …… empty :若迴圈物件為空執行empty內程式碼塊

2、if標籤:邏輯判斷

3、with 標籤: 取別名,簡化變數名

4、csrf_token 標籤:跨站請求偽造保護 {% csrf_token%}

五、自定義模板語法

1、自定義標籤(引數不限,但不能放在if for語句中)- @register.simple_tag

1-1 @register.inclusion_tag --- 返回可迭代物件(qureyset物件)

2、自定義過濾器 - @register.filter



一、模板概念

你可能已經注意到我們在例子檢視中返回文字的方式有點特別。 也就是說,HTML被直接硬編碼在 Python程式碼之中。

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

儘管這種技術便於解釋檢視是如何工作的,但直接將HTML硬編碼到你的視圖裡卻並不是一個好主意。

  • 對頁面設計進行的任何改變都必須對 Python 程式碼進行相應的修改。 站點設計的修改往往比底層 Python 程式碼的修改要頻繁得多,因此如果可以在不進行 Python 程式碼修改的情況下變更設計,那將會方便得多。

  • Python 程式碼編寫和 HTML 設計是兩項不同的工作,大多數專業的網站開發環境都將他們分配給不同的人員(甚至不同部門)來完成。 設計者和HTML/CSS的編碼人員不應該被要求去編輯Python的程式碼來完成他們的工作。

  • 程式設計師編寫 Python程式碼和設計人員製作模板兩項工作同時進行的效率是最高的,遠勝於讓一個人等待另一個人完成對某個既包含 Python又包含 HTML 的檔案的編輯工作。

因此,將頁面的設計和Python的程式碼分離開會更乾淨簡潔更容易維護。 我們可以使用 Django的 模板系統 (Template System)來實現這種模式,這就是本章要具體討論的問題

 python的模板:HTML程式碼+模板語法

# 檢視函式 傳輸資料給模板

def inde_action(request):
    # 推薦寫法
    name = 'name1'
    list00 = [1,2,3,'hello','django']
    dic = {'name':'name2','age':18}

    def test():
        print('hello world')
        return 'fun-test'

    class Person():
        pass

    # locals()方法可以返回檢視函式內所有定義的 變數、函式、類等
    return render(request, 'index.html', locals())

二、 模板語法 - 變數 : {{ 變數 }}

1、直接呼叫輸出 - 相當於print

{#模板語言註釋:前端看不到#}

{#相當於print了該變數#}
<h1>模板語言之變數</h1>

<p>字串:{{ name }}</p>
<p>數字:{{ age }}</p>
<p>列表:{{ ll }}</p>
<p>元組:{{ tu }}</p>
<p>字典:{{ dic }}</p>

{#只寫函式名:相當於函式名(),執行該函式,顯示的是返回值#}
<p>函式:{{ test }}</p>

{#物件呼叫顯示記憶體地址#}
<p>物件:{{ lqz }}</p>

{# person_list=[p1,p2] #}
<p>列表套物件:{{ person_list }}</p>
{# person_dic={'p1':p1} #}
<p>字典套物件:{{ person_dic }}</p>

2、深度取值 - 獲取物件內部值

<h1>深度查詢</h1>

{# 一層 #}
<p>列表第0個值:{{ ll.0 }}</p>
<p>列表第4個值:{{ ll.3 }}</p>
<p>字典取值:{{ dic.name }}</p>
<p>字典取列表值:{{ dic.ll }}</p>

{# 二層 #}
<p>物件取資料屬性:{{ p1.name }}</p>
<p>物件取繫結給物件的函式屬性:{{ p1.get_name }}</p>
<p>物件取繫結給類的函式屬性:{{ p1.cls_test }}</p>
<p>物件取靜態方法:{{ p1.static_test }}</p>
<p>把物件列表中,其中物件的一個年齡屬性取出來:{{ person_list.1.age }}</p>


{# 注意:不能調有引數的方法 #}
<p>字串的方法:{{ name.upper }}</p>

三、模板語法 - 過濾器 :{{ 位置引數1 | 過濾器函式 : 位置引數2}}

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

{{ value|default:"nothing" }}

2- length : 返回值的長度。它對字串和列表都起作用

{{ value|length }}

{#如果 value 是 ['a', 'b', 'c', 'd'],那麼輸出是 4。#}

3- filesizeformat :將值格式化為一個可讀性高的檔案尺寸 

{{ value|filesizeformat }}
{# 如果 value 是 123456789,輸出將會是 117.7 MB #}

4- date :格式化日期

value=datetime.datetime.now()

{{ value|date:"Y-m-d" }} 

{# 不使用date:Nov. 9, 2018, 6:51 p.m. #}

{# date:2018-11-09 #}

5- slice:切片操作

{#前閉後開區間#}
<p>過濾器之slice:{{ ll|slice:'2:-1' }}</p>

{#支援步長#}
<p>過濾器之slice-字串:{{ name|slice:'0:3:3' }}</p>

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

{# 字串 | truncatechars:顯示的詞數(三個起步)#}

<p>過濾器之truncatechars:{{ 'dafddfafgadfgaasdgadgfadaf'|truncatechars:5 }}</p>
{# da... #}

<p>過濾器之truncatewords:{{ '我 dfaf ga dfgaas 你 dgf adaf'|truncatewords:5 }}</p>
{# 我 dfaf ga dfgaas 你 ... #}

7- safe :是否轉義輸入框內的html、js元素等(使用-轉義;不使用-不轉義)

Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,原因顯而易見,這樣是為了安全。

但是有的時候我們可能不希望這些HTML元素被轉義,比如我們做一個內容管理系統,後臺新增的文章中是經過修飾的,這些修飾可能是通過一個類似於FCKeditor編輯加註了HTML修飾符的文字,如果自動轉義的話顯示的就是保護HTML標籤的原始檔。

為了在Django中關閉HTML的自動轉義,通過過濾器“|safe”的方式告訴Django這段程式碼是安全。

{# h1='<h1>你好</h1>' #}
<p>過濾器之不用safe:{{ h1 }}</p>
<p>過濾器之用safe:{{ h1|safe }}</p>

{# script='<script>alert(111)</script>' #}
<p>過濾器之不用safe:{{ script }}</p>
<p>過濾器之用safe:{{ script|safe }}</p>

8- 其他過濾器

過濾器 描述 示例
upper 以大寫方式輸出 {{ user.name | upper }}
add 給value加上一個數值 {{ user.age | add:”5” }}
addslashes 單引號加上轉義號  
capfirst 第一個字母大寫 {{ ‘good’| capfirst }} 返回”Good”
center 輸出指定長度的字串,把變數居中 {{ “abcd”| center:”50” }}
cut 刪除指定字串 {{ “You are not a Englishman” | cut:”not” }}
date 格式化日期  
default 如果值不存在,則使用預設值代替 {{ value | default:”(N/A)” }}
default_if_none 如果值為None, 則使用預設值代替  
dictsort 按某欄位排序,變數必須是一個dictionary {% for moment in moments | dictsort:”id” %}
dictsortreversed 按某欄位倒序排序,變數必須是dictionary  
divisibleby 判斷是否可以被數字整除 {{ 224 | divisibleby:2 }} 返回 True
escape 按HTML轉義,比如將”<”轉換為”&lt”  
filesizeformat 增加數字的可讀性,轉換結果為13KB,89MB,3Bytes等 {{ 1024 | filesizeformat }} 返回 1.0KB
first 返回列表的第1個元素,變數必須是一個列表  
floatformat 轉換為指定精度的小數,預設保留1位小數 {{ 3.1415926 | floatformat:3 }} 返回 3.142 四捨五入
get_digit 從個位數開始擷取指定位置的數字 {{ 123456 | get_digit:’1’}}
join 用指定分隔符連線列表 {{ [‘abc’,’45’] | join:’’ }} 返回 abc45
length 返回列表中元素的個數或字串長度  
length_is 檢查列表,字串長度是否符合指定的值 {{ ‘hello’| length_is:’3’ }}
linebreaks 用<p>或<br>標籤包裹變數 {{ “Hi\n\nDavid”|linebreaks }} 返回<p>Hi</p><p>David</p>
linebreaksbr 用<br/>標籤代替換行符  
linenumbers 為變數中的每一行加上行號  
ljust 輸出指定長度的字串,變數左對齊 {{‘ab’|ljust:5}}返回 ‘ab ’
lower 字串變小寫  
make_list 將字串轉換為列表  
pluralize 根據數字確定是否輸出英文複數符號  
random 返回列表的隨機一項  
removetags 刪除字串中指定的HTML標記 {{value | removetags: “h1 h2”}}
rjust 輸出指定長度的字串,變數右對齊  
slice 切片操作, 返回列表 {{[3,9,1] | slice:’:2’}} 返回 [3,9] {{ 'asdikfjhihgie' | slice:':5' }} 返回 ‘asdik’
slugify 在字串中留下減號和下劃線,其它符號刪除,空格用減號替換 {{ '5-2=3and5 2=3' | slugify }} 返回 5-23and5-23
stringformat 字串格式化,語法同python  
time 返回日期的時間部分  
timesince 以“到現在為止過了多長時間”顯示時間變數 結果可能為 45days, 3 hours
timeuntil 以“從現在開始到時間變數”還有多長時間顯示時間變數  
title 每個單詞首字母大寫  
truncatewords 將字串轉換為省略表達方式 {{ 'This is a pen' | truncatewords:2 }}返回``This is ...
truncatewords_html 同上,但保留其中的HTML標籤 {{ '<p>This is a pen</p>' | truncatewords:2 }}返回``<p>This is ...</p>
urlencode 將字串中的特殊字元轉換為url兼容表達方式 {{ ‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}}
urlize 將變數字串中的url由純文字變為連結  
wordcount 返回變數字串中的單詞數  
yesno 將布林變數轉換為字串yes, no 或maybe {{ True | yesno }}{{ False | yesno }}{{ None | yesno }} ``返回 ``yes``no ``maybe

四、模板語法 - 標籤 : {% tag %} …… {% endtag%}

標籤比變數更加複雜:一些在輸出中建立文字,一些通過迴圈或邏輯來控制流程,一些載入其後的變數將使用到的額外資訊到模版中。一些標籤需要開始和結束標籤 (例如{% tag %} ...標籤 內容 ... {% endtag %})。

1- for標籤:迴圈結構

列表的迴圈:

    {% for person in person_list %}
        <p>{{ person.name }}</p>
    {% endfor %}

字典的迴圈:

    {% for key in dic %}
        <p>{{ key }}</p>
    {% endfor %}

    {% for val in dic.values %}
        <p>{{ val }}</p>
    {% endfor %}

    {% for key,val in dic.items %}
        <p>{{ key }}:{{ val }}</p>
    {% endfor %}


模板:
    {% for i in list %}
        {{ i }}
    {% endfor %}

1-1 檢視迴圈資訊:{{ forloop }}

{% for foo in ll %}
    {{ forloop }}
<p>{{ forloop.first }}--->{{ forloop.counter0 }}--->{{ forloop.revcounter }}----->{{ foo }}</p>
{% endfor %}



{% for foo in ll %}
    {% for i in person_list %}
          取出外層是第幾次迴圈
        {{ forloop.parentloop.counter }}
        <p>{{ forloop.first }}--->{{ forloop.counter0 }}--->{{ forloop.revcounter }}----->{{ foo }}</p>
    {% endfor %}
{% endfor %}

{{ forloop }}的輸出資訊:

{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 4, 'revcounter0': 3, 'first': True, 'last': False} 

 

forloop.counter   當前迴圈的索引值(從1開始)
forloop.counter0 當前迴圈的索引值(從0開始)
forloop.revcounter 當前迴圈的倒序索引值(從1開始)
forloop.revcounter0  當前迴圈的倒序索引值(從0開始)
forloop.first  當前迴圈是不是第一次迴圈(布林值)
forloop.last 當前迴圈是不是最後一次迴圈(布林值)
forloop.parentloop 本層迴圈的外層迴圈

1-2 for …… empty :若迴圈物件為空執行empty內程式碼塊

{% for person in person_list %}
    <p>{{ person.name }}</p>

{% empty %}
    <p>sorry,no person here</p>
{% endfor %}

2、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 %}


模板(if語句支援 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷):
    {% if …… %}
        ……
    {% elif …… %}
        ……
    {% else %}
        ……
    {% endif %}

3、with 標籤: 取別名,簡化變數名

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}


模板:
    {% with 別名=原名 %}
        {{ 別名 }}
        ……
    {% endwith %}

4、csrf_token 標籤:跨站請求偽造保護 {% csrf_token%}

五、自定義模板語法

1、自定義標籤(引數不限,但不能放在if for語句中)- @register.simple_tag

  1. 確認app在setting內的INSTALLED_APPS註冊
  2. app下建立一個templatetags(固定名稱)的資料夾(模組)
  3. 建立任意 .py 檔案,如:my_tags.py
    # 第一步,匯入template
    from django import template #或者 from django.template import Library
    from django.utils.safestring import mark_safe
     
    register = template.Library()   #register的名字是固定的,不可改變
     
    
    @register.simple_tag(name = 'xxx') 裝飾器內name可以對方法起別名
    def simple_tag_multi(v1,v2):
        return  v1 * v2 #一定要有返回值
    
    @register.simple_tag
    def my_input(id,arg):
        result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
        return mark_safe(result)

     

  4. 在模板裡:(新定定義的標籤,過濾器,都要重啟程式)
    {# 載入自己的標籤檔名 #}
    {% load mytag %}
    
    {# 使用標籤 #}
    {% add_nb 'name'%}
    {% add_3 'name1' 'name2'%} 多個引數以空格區分
    

     

1-1 @register.inclusion_tag --- 返回可迭代物件(qureyset物件)

注意:普通的自定義標籤返回的都只是一個值,而inclusion_tag返回一個可迭代物件

# 第一步,匯入template
from django import template #或者 from django.template import Library
 
register = template.Library()   #register的名字是固定的,不可改變
 

# @register.inclusion_tag('模板路徑',name=‘重新命名’)  
@register.inclusion_tag('test.html',name = 'xxx') 裝飾器內name可以對方法起別名
def my_inclusion_1():

    # 邏輯程式碼塊……

    ret = Book.object.all()

    return {'books':ret} # 一定要有返回值,並且返回值必須是字典

@register.inclusion_tag('test.html')
def my_inclusion_2(v1,v2):

    # 邏輯程式碼塊……

    ret = Book.object.all().filter(v1=v1,v2=v2)

    return {'books':ret}

 

{# 模板中使用自定義inclusion_tag #}

{# 載入自己的標籤檔名 #}
{% load mytag %}

{# 使用標籤 #}
{% my_inclusion_1 %}
{% my_inclusion_2 'v1' 'v2'%} 多個引數以空格區分

2、自定義過濾器 - @register.filter

  1. 確認app在setting內的INSTALLED_APPS註冊
  2. app下建立一個templatetags(固定名稱)的資料夾(模組)
  3. 建立任意 .py 檔案,如:my_filter.py
    # 第一步,匯入template
    from django.template import Library
    
    # 第二步,定義一個叫register的變數=template.Library()
    register = Library()
    
    
    # 第三步
    
    # 裝飾器內name可以對方法起別名
    @register.filter(name='yyy') 
    def str_add(str1, str2):
        # 業務邏輯……
        return str1 + str2 # 一定要有返回值

     

  4. 在模板裡:(新定定義的標籤,過濾器,都要重啟程式)
    匯入自己建立的過濾器檔案
    {% load myfilter %}
    
    {{'name'|str_add:'hello'}}