django 模版 語法與使用

  • 2019 年 10 月 8 日
  • 筆記

目錄

django 模版語法與使用

django模板語言介紹 (摘自官方文檔) 鏈接

""" Django模板語言 Django的模板語言旨在在功能和易用性之間取得平衡。它讓那些習慣使用HTML的人感到舒服。 如果您對其他基於文本的模板語言(如Smarty 或Jinja2)有過接觸,那麼您應該對Django的模板感到賓至如歸。 哲學 如果您有編程背景,或者習慣於將編程程式碼直接混合到HTML中的語言,那麼您需要記住, Django模板系統不僅僅是嵌入到HTML中的Python。這是一種設計,模板系統用於表達,而不是程式邏輯。 Django模板系統提供的標籤功能類似於一些編程結構 如 if,布爾,for標籤,循環標籤等 - 但這些標籤不是簡單地作為相應的Python程式碼執行, 模板系統不會執行任意Python表達式。默認情況下,僅支援下面列出的標記,過濾器和語法(您可以根據需要將自己的擴展添加到模板語言中)。 哲學 為什麼使用基於文本的模板而不是基於XML的模板(如Zope的TAL)?我們希望Django的模板語言不僅可用於XML / HTML模板。 在World Online,我們將其用於電子郵件,JavaScript和CSV。您可以將模板語言用於任何基於文本的格式。 哦,還有一件事:讓人類編輯XML是虐待狂! """

什麼是模板?

模板只是一個文本文件。它可以生成任何基於文本的格式(HTML,XML,CSV等)。 模板包含變數,這些變數在評估模板時將替換為值,而變數則包含控制模板邏輯的標記。 只要是在html裡面有模板語法就不是html文件了,這樣的文件就叫做模板。

模板語句的 注釋

模板語句的注釋  {#{{ '10'|add_str:'5 '}}#}  {#注釋內容#}    

變數 {{ 變數 }}

  • 變數:語法為 {{ }}:括弧里加要渲染變數的變數值,變數名由字母數字和下劃線組成。
  • 程式碼
#views 文件函數  def template_test(request):      name = '鋼蛋'      age = 18      hobby = ['唱', '跳', 'rap', '籃球']      lis = []      st = ''      dic = {          'name': '鐵蛋',          'age': 16,          'hobby': hobby,          'keys': 'xxxxx'      }      dic_2 = {}      return render(request,'template_test.html',   {'name':name_p,'age':age,'hobby':hobby,'lis':lis,'st':st,'dic':dic,'dic_2':dic_2})    # 模板文件html頁面  <!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>郭楷豐</title>  </head>  <body>  {{ 啦啦啦啦啦 }}  <p>      {{ name }}  </p>  <p>     {{ age }}  </p>  <p>      {{ hobby }}  </p>  <p>      {{ lis }}  </p>  <p>      {{ st }}  </p>  <p>      {{ dic }}  </p>  <p>      {{ dic_2 }}  </p>  </body>  </html>
  • 瀏覽器結果:
  • 小結: {{ }}里填要渲染的變數,規範寫法,兩邊用括弧隔開 如 {{ 變數 }}, 後端沒有傳參的頁面不顯示

點(.)在模板語言中有特殊的含義,用來獲取對象的相應屬性值。

  • 例子 程式碼 .索引 .key .屬性 .方法
#views 文件函數  def template_test(request):      lis = [1, 2, 3,4,5]      dic = {"name": "黑蛋"}        class Person(object):          def __init__(self, name, age):              self.name = name              self.age = age            def dream(self):              return " 我 is {} age {}歲...".format(self.name,self.age)        gangdan = Person(name="鋼蛋", age=18)      goudan = Person(name="狗蛋", age=17)      tiedan  = Person(name="鐵蛋", age=16)        person_list = [gangdan, goudan, tiedan]      return render(request, "template_test.html", {"lis": lis, "dic": dic, "person_list": person_list})    # 模板文件html頁面  <!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>郭楷豐</title>  </head>  <boby>      <p>{{ lis.0 }}</p>   <!--取l中的第一個參數-->      <p>{{ dic.name }}</p><!--取字典中key的值-->      <p>{{ person_list.0.name }}</p><!--取對象的name屬性-->      <p>{{ person_list.0.dream }}</p><!--.操作只能調用不帶參數的方法-->  </boby>  </html>
  • 小結:
#註:當模板系統遇到一個(.)時,會按照如下的順序去查詢:  1. 在字典中查詢  2. 屬性或者方法  3. 數字索引   # 索引不能為負數

Tags 標籤 {% %} 表示邏輯相關的操作

  • 程式碼例子
{% for foo in lis %}  <!--for循環-->      {% if  %}      <!--if判斷-->      {% elif %}      <!--elif判斷-->      {% endif %}      <!--if閉合符-->      {% else %}      <!--else判斷不成立執行-->  {% endfor %}  <!--for循環閉合符-->    <!--應用 模板html程式碼-->  <form action="" method="post">      <label for="inputEmail3" class="col-sm-2 control-label">書名: </label>      <div class="col-sm-8">          <input type="text" name="book_name" class="form-control" value="{{ edit_obj.title }}">          <select name="pub_id" id="" class="btn btn-default  btn-sm">              {% for foo in publishers %}              {% if foo == edit_obj.pub %}              <option selected value="{{ foo.pk }}"> {{ foo.name }}</option>              {% else %}              <option value="{{ foo.pk }}"> {{ foo.name }}</option>              {% endif %}              {% endfor %}          </select>      </div>      <div class="text-center text-danger">{{ error }}</div>      <div class="col-sm-offset-2 col-sm-10">          <button type="submit" class="btn btn-default">提交</button>      </div>  </form>    <!--應用 python邏輯程式碼 #views 文件函數-->  def edit_book(request):      error = ''      pk = request.GET.get('pk')      edit_obj = models.Book.objects.filter(id=pk)      if not edit_obj:          return HttpResponse('要編輯的數據不存在')      if request.method == 'POST':          book_name = request.POST.get('book_name')          if not book_name.strip():              error = "書名不能為空"          pub_id = request.POST.get('pub_id')          if edit_obj[0].title == book_name and edit_obj[0].pub_id == int(pub_id):              error = "未作修改"          if not error:              obj = edit_obj[0]              obj.title = book_name              obj.pub_id = int(pub_id)              obj.save()              return redirect('/book_list/')      publishers = models.Publisher.objects.all()      return render(request,'edit_book.html',{'edit_obj':edit_obj[0],'publishers':publishers,'error':error})
  • 執行效果
  • if語句支援 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷。
  • js,python,模板語言的判斷邏輯 #python 10>5>1 =》 10>5 and 5>1 true #js 10>5>1 =》 10>5 =》 true =》 1>1 false #模板中 不支援連續連續判斷,也不支援算數運算(過濾器)
  • 注意事項
  • 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的值。

for循環可用的一些參數:

Variable

Description

forloop.counter

當前循環的索引值(從1開始)

forloop.counter0

當前循環的索引值(從0開始)

forloop.revcounter

當前循環的倒序索引值(到1結束)

forloop.revcounter0

當前循環的倒序索引值(到0結束)

forloop.first

當前循環是不是第一次循環(布爾值)

forloop.last

當前循環是不是最後一次循環(布爾值)

forloop.parentloop

本層循環的外層循環

  • for ... empty
#for 標籤帶有一個可選的{% empty %} 從句,以便在給出的組是空的或者沒有被找到時,可以有所操作。  {% for person in person_list %}      <p>{{ person.name }}</p>  {% empty %}      <p>sorry,no person here</p>  {% endfor %}

Filters 過濾器

  • 用來修改變數的顯示結果, 語法: {{ value|filter_name:參數 }} ':' 左右沒有空格沒有空格沒有空格
  • 設置除法除盡 divisibleby:參數

with 的使用

  • 定義一個中間變數(起個別名,只在with內部生效)
#寫法一  {% with total=business.employees.count %}      {{ total }} employee{{ total|pluralize }}  {% endwith %}    #寫法二  {% with business.employees.count as total %}      {{ total }} employee{{ total|pluralize }}  {% endwith %}

default 系統默認值

{{ value|default:"nothing"}}  如果value值沒傳的話就顯示nothing  註:TEMPLATES的OPTIONS可以增加一個選項:string_if_invalid:'找不到',可以替代default的的作用。  (在配置文件settings.py設置)
  • 配置設置變數不傳參顯示值
  • 頁面效果

filesizeformat 文件大小人性化顯示

  • 將值格式化為一個 「人類可讀的」 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)例如:
{{ value|filesizeformat }}  如果 value 是 123456789,輸出將會是 117.7 MB

add "加"

  • 給變數加參數,字元串默認嘗試轉int類型,轉不了就拼接
{{ value|add:"2" }}  value是數字4,則輸出結果為6    {{ value|add:"hello" }}  value是數字666,則輸出結果為666hello    {{ first|add:second }}  如果first是 [1,.2,3] ,second是 [4,5,6] ,那輸出結果是 [1,2,3,4,5,6] 

lower 小寫

{{ value|lower }}

upper 大寫

{{ value|upper}}

title 標題

{{ value|title }}

ljust 左對齊

"{{ value|ljust:"10" }}"

rjust 右對齊

"{{ value|rjust:"10" }}"

center 居中

"{{ value|center:"15" }}"

length 長度

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

slice 切片

{{value|slice:"2:-1"}}

first 取第一個元素

{{ value|first }}

last 取最後一個元素

{{ value|last }}

join 使用字元串拼接列表

  • 同python的str.join(list)
{{ value|join:" // " }}

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

  • 如果value為'i love you',那麼將輸出'iloveyou'.
{{ value|cut:' ' }}

truncatechars 按照字元截斷 ...也計數

  • 如果字元串字元多於指定的字元數量,那麼會被截斷。截斷的字元串將以可翻譯的省略號序列(「...」)結尾
#參數:截斷的字元數  {{ value|truncatechars:9}}    truncatewords 按照單詞進行截斷, 只針對英文(...)不計數,中文按字計算

date 日期格式化

#後端  import datetime  def mul(request):      value = datetime.datetime.now()      return render(request, 'mul.html',{'value':value})    #模板語句  {{ value|date:"Y-m-d H:i:s"}}   #顯示格式 年-月-日 時:分:秒      #後端  import datetime  def mul(request):      now = datetime.datetime.now()      return render(request, 'mul.html',{'now':now})    #模板直接使用變數  {{ now }}  #顯示格式 June 19,2019,22:00 p.m.    #時間格式和默認值一起使用  {{ obj.next_date|date:"Y-m-d"|default:"暫無" }}
  • 頁面效果
  • 可格式化輸出的字元: 點擊查看
  • 改配置文件設置顯示樣式 (一勞永逸的解決辦法)
#settings.py文件設置  USE_L10N = False  #更換為False    DATETIME_FORMAT = 'Y-m-d H:i:s' #添加    #也可以日期與時間分開設置  根據自己的需求設置  DATE_FORMAT = 'Y-m-d'  TIME_FORMAT = 'H:i:s'

safe 防止xss攻擊 作用 取消轉義

  • 簡單了解xss攻擊

XSS攻擊全稱跨站腳本攻擊,是為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆, 故將跨站腳本攻擊縮寫為XSS,XSS是一種在web應用中的電腦安全漏洞,它允許惡意web用戶將程式碼植入到提供給其它用戶使用的頁面中。 XSS是一種經常出現在web應用中的電腦安全漏洞,它允許惡意web用戶將程式碼植入到提供給其它用戶使用的頁面中。 比如這些程式碼包括HTML程式碼和客戶端腳本。攻擊者利用XSS漏洞旁路掉訪問控制——例如同源策略(same origin policy)。 這種類型的漏洞由於被駭客用來編寫危害性更大的網路釣魚(Phishing)攻擊而變得廣為人知。對於跨站腳本攻擊, 駭客界共識是:跨站腳本攻擊是新型的「緩衝區溢出攻擊「,而JavaScript是新型的「ShellCode」。

  • xss攻擊流程

safe 主要作用

#Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,原因顯而易見,這樣是為了安全。 但是有的時候我們可能不希望這些HTML元素被轉義,比如我們做一個內容管理系統,後台添加的文章中是經過修飾的, 這些修飾可能是通過一個類似於FCKeditor編輯加註了HTML修飾符的文本,如果自動轉義的話顯示的就是保護HTML標籤的源文件。 為了在Django中關閉HTML的自動轉義有兩種方式,如果是一個單獨的變數我們可以通過過濾器「|safe」的方式告訴Django這段程式碼是安全的不必轉義。

  • 正常情況下
#頁面程式碼:  {% load my_tags %}  {{ 'https://www.baidu.com/'|show:'百度' }}    #自定過濾器程式碼  @register.filter  def show(url,name):      return "<a href = '{}'>{}</a>".format(url,name)
  • 頁面顯示效果
  • 過濾器函數 加is_safe = True 解除轉義
#自定過濾器程式碼  @register.filter(is_safe = True)  def show(url,name):      return "<a href = '{}'>{}</a>".format(url,name)
  • 頁面效果
  • 模板語句中加 safe 解除轉義
#模板語句  {% load my_tags %}  {{ 'https://www.baidu.com/'|show:'百度'|safe }}
  • 頁面效果
  • 也可以導入模組實現這種效果

自定義 filter

  • 當普通的內置過濾器,實現不了我們的開發需求,那我們可以自定義過濾器來實現功能
自定義過濾器是只能帶有一個或兩個參數的Python函數:  變數(輸入)的值 - -不一定是一個字元串  參數的值 - 這可以有一個默認值,或完全省略  例如,在過濾器{{var | foo:「bar」}}中,過濾器foo將傳遞變數var和參數「bar」。  自定義filter程式碼文件擺放位置:  app01/      __init__.py      models.py      templatetags/  # 在app01下面新建一個package package          __init__.py          app01_filters.py  # 建一個存放自定義filter的py文件      views.py

自定義過濾器流程

  • 1 在app下創建一個名為templatetags的python包
#注意  在settings中的INSTALLED_APPS配置當前app,不然django無法找到自定義的simple_tag    (模組名只能是templatetags)
  • 2 在python中創建py文件,文件名可以自定義 如:(my_tags.py)
  • 3 在py文件中寫:
from django import template    register = template.Library()  #固定寫法,不可改變
  • 4 寫函數+裝飾器
@register.filter  #過濾器  def add_str(value, arg):  # 最多有兩個      return '{}-{}'.format(value, arg)
  • 5 寫頁面程式碼 在使用自定義simple_tag和filter的html文件中導入之前創建的 my_tags.py
{% load my_tags %}   #先導入我們自定義那個文件 my_tags  {{ name|add_str:age }}   #參數只能是兩個,一個參數是變數name ,一個是參數是後面的那個參數age
  • 執行結果
  • 自定義乘法過濾器 multioly
#過濾器函數  @register.filter  def multiply1(value,arg):      return value * arg    #模板語句  {% load my_tags %}  <p>{{ 6|multiply1:'6' }}</p>  <p>{{ 6|multiply1:6 }}</p>  <p>{{ '10'|multiply1:5 }}</p>
  • 執行結果
  • 自定義除法過濾器 division
#過濾器函數  @register.filter  def division(value,arg):      return value / arg    #模板語句  {% load my_tags %}  <p>{{ 6|division:6 }}</p>  <p>{{ 6|division:1 }}</p>
  • 執行結果
  • 自定義除法過濾器 add
#過濾器函數  @register.filter  def add(value,arg):      return value + arg   #可以這樣寫,但是轉換不了會報錯 int(value) + int(arg)    #模板語句  {% load my_tags %}  <p>{{ 6|add:6 }}</p>  <p>{{ 6|add:0 }}</p>    <p>{{ '鋼蛋g'|add:18 }}</p>
  • 執行結果
  • 自定義減法過濾器 subtraction
#過濾器函數  @register.filter  def add(value,arg):      return value - arg    #模板語句  {% load my_tags %}  <p>{{ 6|add:6 }}</p>  <p>{{ 6|add:0 }}</p>
  • 執行結果

自定義標籤 simpletag

  • 與自定義過濾器區別,可以接受更多參數,使用標籤引用{{% %}
與自定義filter類似(也是在python包的templatetags文件下,創建此標籤),只不過接收更靈活的參數。    #simple_tag  程式碼  @register.simple_tag(name="plus")  def plus(a, b, c):      return "{} + {} + {}".format(a, b, c)    #使用simple tag  自定義標籤  {% load app01_demo %}  {# simple tag #}  {% plus "1" "2" "abc" %}      #例子  標籤程式碼  @register.simple_tag  def join_str(*args, **kwargs):      return '{} - {} '.format('*'.join(args), '$'.join(kwargs.values()))    # 模板  {% load my_tags %}  {% join_str '1' '2' '鋼蛋' k1='3' k2='4' %}    
  • 執行效果

自定義標籤 inclusion_tag

  • 多用於返回html程式碼片段 (動態變數 分頁)
  • app文件下 創建python包
  • 包文件名必須為 templatetags
  • 在templatetags裡面創建任意 .py 文件
  • 寫函數
  • html頁面程式碼 #分頁顯示程式碼 <nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">&laquo;</span> </a> </li> {% for i in num %} <li><a href="#">{{ i }}</a></li> {% endfor %} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">&raquo;</span> </a> </li> </ul> </nav> #頁面1 {% load my_tags %} {% page 5 %} #頁面2 {% load my_tags %} {% page 1 %}
  • 顯示效果
  • 總結:
自定義過濾器 filter 只能接受兩個參數 調用的時候使用 {{ filter }}    自定義標籤  simpletag  與自定義過濾器區別,可以接受更多參數,使用標籤引用{{%  %}    自定義標籤 inclusion_tag  多用於返回html程式碼片段,使用標籤引用{{% %}                                   

csrf_token 跨站請求偽造保護

在頁面的form表單裡面寫上{% csrf_token %}
  • 如圖

靜態文件相關

#作用 在配置文件找到靜態文件別名,與文件地址進行拼接,這樣別名改了,也不會影響,靜態文件的導入    {% load static %}  <img src="{% static "images/hi.jpg" %}" alt="Hi!" />    #引用JS文件時使用:  {% load static %}  <script src="{% static "mytest.js" %}"></script>    #某個文件多處被用到可以存為一個變數  {% load static %}  {% static "images/hi.jpg" as myphoto %}  <img src="{{ myphoto }}"></img>      {% load static %}   <link rel="stylesheet" href="{% static '/plugins/bootstrap-3.3.7/css/bootstrap.css' %}">   <link rel="stylesheet" href="{% static '/css/dsb.css' %}">  {% static '/plugins/bootstrap-3.3.7/css/bootstrap.css' %}    {% get_static_prefix %}   # 獲取別名
  • 獲取配置文件的 別名

母版和繼承

什麼是母版?

普通的HTML頁面 母版頁用於處理html頁面相同部分內容,避免出現冗餘程式碼,減少重複html頁面的編寫,提高程式碼復用性,方便程式碼修改.

繼承寫法

#在子頁面中在頁面最上方使用下面的語法來繼承母板。  {% extends '母版文件名.html' %}

block 塊

通過在母板中使用{% block  xxx %}來定義"塊"。  在子頁面中通過定義母板中的block名來對應替換母板中相應的內容。    #定義block  {% block 塊名 %}  {% endblock  %} #還可以{{% endblock 塊名 %}}來關閉標籤,更加清新    #使用block  {% block 塊名 %}        #自己的內容    {% endblock  %}    #母版內容和自己內容都使用  {% block 塊名 %}        #自己的內容      {% block.super %}    {% endblock  %}

子頁面替換母版 block塊

  • 注意事項
注意的點:    1. {% extends 'base.html' %} 寫在第一行   前面不要有內容 有內容會顯示  2. {% extends 'base.html' %}  'base.html' 加上引號   不然當做變數去查找  3. 把要顯示的內容寫在block塊中  4. 定義多個block塊,定義 css  js 塊

組件

#作用  可以將常用的頁面內容如導航條,頁尾資訊等組件保存在單獨的文件中,然後在需要使用的地方按如下語法導入即可。    #示列  單獨建一個html  page  <nav aria-label="Page navigation">    <ul class="pagination">      <li>        <a href="#" aria-label="Previous">          <span aria-hidden="true">&laquo;</span>        </a>      </li>      {% for i in num %}          <li><a href="#">{{ i }}</a></li>      {% endfor %}      <li>        <a href="#" aria-label="Next">          <span aria-hidden="true">&raquo;</span>        </a>      </li>    </ul>  </nav>    #別的頁面 引用  {% include 'page.html' %}

作 者:郭楷豐

Tags: