04 Django之模板系統

一.語法css

  關於模板渲染只須要記住兩種特殊符號(語法):html

  {{ }} 和 {% %}  (變量相關用{{ }}  邏輯相關用{% %})前端

二.變量python

  在Django的模板語言中按照{{ 變量名 }}來使用.數據庫

  當模板引擎遇到一個變量,它將計算這個變量,而後用結果替換掉它的自己django

  注意事項後端

    1.若是計算結果的值是可調用的,它將被無參數的調用.調用的結果將成爲模板的值.瀏覽器

    2.若是使用的變量不存在,模板系統將插入string_if_invalid選項的值,它被默認設置爲"(空字符串)"緩存

  例子:安全

      views.py  中的代碼

def index(request):
    import datetime
    s = "hello"
    l = [111, 222, 333]  # 列表
    dic = {"name": "yuan", "age": 18}  # 字典
    date = datetime.date(1993, 5, 2)  # 日期對象

    class Person(object):
        def __init__(self, name):
            self.name = name
        def dream(self):
            return 'dreamer'
    person_yuan = Person("chao")  # 自定義類對象
    person_egon = Person("yantao")
    person_alex = Person("jinxin")

    person_list = [person_yuan, person_egon, person_alex]

    return render(request, "index.html", {"l": l, "dic": dic, "date": date, 
"person_list": person_list}) # return render(request,'index.html',locals()) #locals()獲取函數內容全部的變量,而後經過render方法給了index.html文件進行模板渲染,
若是你圖省事,你能夠用它,可是不少多餘的變量也被傳進去了,效率低

    模板中的寫法:

<h4>{{s}}</h4>
<h4>列表:{{ l.0 }}</h4>
<h4>列表:{{ l.2 }}</h4>
<h4>字典:{{ dic.name }}</h4>
<h4>日期:{{ date.year }}</h4>

<!--取列表的第1個對象的name屬性的值-->
<h4>類對象列表:{{ person_list.0.name }}</h4>
<!--取列表的第1個對象的dream方法的返回值,若是沒有返回值,拿到的是none-->
<h4>類對象列表:{{ person_list.0.dream }}</h4>

注意:
    調用對象裏面的方法的時候,不須要寫括號來執行,而且執行不須要傳參數的方法,若是你的這個方法 
須要傳參數,那麼模板語言不支持,不能幫你渲染

  

三.過濾器

  在Django的模板語言中,經過使用 過濾器來改變變量的顯示.

  過濾器的語法: {{ vlaue|filter_name:參數}}

  使用管道符來應用過濾器

  例如:{{ name|lower }} 會將name變量應用lower過濾器以後再顯示它的值.lower的做用是將文本所有變成小寫.

  注意事項:

  1. 過濾器支持「鏈式」操做。即一個過濾器的輸出做爲另外一個過濾器的輸入。
  2. 過濾器能夠接受參數,例如:{{ sss|truncatewords:30 }},這將顯示sss的前30個詞。
  3. 過濾器參數包含空格的話,必須用引號包裹起來。好比使用逗號和空格去鏈接一個列表中的元素,如:{{ list|join:', ' }}
  4. '|'左右沒有空格沒有空格沒有空格

  default 

    若是一個變量是false或者爲空,使用給定的默認值,不然,使用變量的值

{{ value|default:"nothing"}}

    若是value沒有傳值或者值爲空的時候就顯示nothing

  length

    返回值的長度,做用於字符串和列表.

    {{ value|length}}

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

  filesizeformat

    將值格式化爲一個"人類可讀的"文件尺寸  (例如: '13 KB''4.1 MB''102 bytes', 等等).

{{ value|filesizeformat}}

    若是 value 是 123456789,輸出將會是 117.7 MB。

  slice

    切片,若是value="hello world" ,還有其餘可切片的數據類型

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

  date

    格式化,若是value=datetime.datetime.now()

{{ value|date:"Y-m-d H:i:s"}}

  關於時間日期的可用的參數(除了Y,m,d等等)還有不少

  safe

    

Django的模板中在進行模板渲染的時候會對HTML標籤和JS等語法標籤進行自動轉義,緣由顯而易見,這樣是爲了安全,django擔憂這是用戶添加的數據,好比若是有人給你評論的時候寫了一段js代碼,這個評論一提交,js代碼就執行啦,這樣你是否是能夠搞一些壞事兒了,寫個彈窗的死循環,那瀏覽器還能用嗎,是否是會一直彈窗啊,這叫作xss攻擊,因此瀏覽器不讓你這麼搞,給你轉義了。可是有的時候咱們可能不但願這些HTML元素被轉義,好比咱們作一個內容管理系統,後臺添加的文章中是通過修飾的,這些修飾多是經過一個相似於FCKeditor編輯加註了HTML修飾符的文本,若是自動轉義的話顯示的就是保護HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,若是是一個單獨的變量咱們能夠經過過濾器「|safe」的方式告訴Django這段代碼是安全的沒必要轉義。

    咱們去network那個地方看看,瀏覽器看到的都是渲染以後的結果,經過network的response的那個部分能夠看到,這個a標籤所有是特殊符號包裹起來的,並非一個標籤,這都是django搞得事情。

    好比:

      value = "<a href='#'>點我</a>"   和   value="<script>alert('123')</script>"

{{ value|safe}}

  truncatechars

    若是字符串字符多於指定的字符數量,那麼會被截斷.截斷的字符串將能夠翻譯的聖羅浩代替("...")結尾

    參數:截端的字符數

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

  truncatewords

    在必定的數量的字後面截斷字符串,是截斷多少個單詞

    例如:‘hello girl hi baby yue ma’,

{{ value|truncatewords:3}}  #上面例子獲得的結果是 'hello girl h1...'

  cut

    移除value中全部的與給出的變量相同的字符串

{{ value|cut:' ' }}

  join

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

四 標籤Tags

  標籤看起來像是{% tag %}. 標籤比變量更復雜:一些在輸出中建立文本,一些經過循環或邏輯來控制流程,一些加載其後的變量將使用到的額外信息到模板中.一些標籤須要開始和結束標籤(例如{% tag %} ...標籤 內容 ... {% endtag %})。

   for標籤

    遍歷每個元素:寫一個for,而後tab鍵自動生成for循環的結構,沒有break之類的,複雜一些的功能,須要經過js

{% for person in person_list %}
    <p>{{ person.name }}<p>  <!--凡是變量就都要用兩個大括號括起來-->
{% endfor %}

   能夠利用{% for obj in list reversed %}反向完成循環。 

    遍歷字典

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

  注:循環序號能夠經過{{forloop}}顯示,必須在循環內部用

forloop.counter            當前循環的索引值(從1開始),forloop是循環器,經過點來使用功能
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 %}

  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判斷,注意條件兩邊都有空格。

   with 

    使用一個簡單的名字緩存一個複雜的變量,多用於給一個複雜的變量起別名,當你須要使用一個"昂貴的方法"(好比訪問數據庫)不少次的時候是頗有用的

    例如:

    等號左右不要加空格

{% with total=business.employees.count%}
    {{ total }}  只能在with語句體裏使用
{% endwith %}

  或者

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

  csrf_token

    咱們以post方式提交表單的時候,會報錯,還記得咱們在settings裏面的中間件配置裏面把一個csrf的防護機制給註銷了啊,自己不該該註銷的,而是應該學會怎麼使用它,而且不讓本身的操做被forbiden,經過這個東西就能搞定。

    這個標籤用於跨站請求僞造保護

     在頁面的form表單裏面(注意是在form表單裏面)任何位置寫上{% csrf_token %},這個東西模板渲染的時候替換成了<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">,隱藏的,這個標籤的值是個隨機字符串,提交的時候,這個東西也被提交了,首先這個東西是咱們後端渲染的時候給頁面加上的,那麼當你經過我給你的form表單提交數據的時候,你帶着這個內容我就認識你,不帶着,我就禁止你,由於後臺咱們django也存着這個東西,和你這個值相同的一個值,能夠作對應驗證是否是我給你的token,存儲這個值的東西咱們後面再學,你先知道一下就好了,就像一個咱們後臺給這個用戶的一個通行證,若是你用戶沒有按照我給你的這個正常的頁面來post提交表單數據,或者說你沒有先去請求我這個登錄頁面,而是直接模擬請求來提交數據,那麼我就能知道,你這個請求是非法的,反爬蟲或者惡意攻擊個人網站,之後將中間件的時候咱們在細說這個東西,可是如今你要明白怎麼回事,明白爲何django會加這一套防護。

 五 模板繼承

  Django模板引擎中最強大的也是最複雜的部分就是模板繼承.模板繼承可讓你建立一個基本的骨架模板,它包含您站點的所有元素,而且能夠定義可以被子木板覆蓋的blocks.

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}My amazing site{%/span> endblock %}</title>
</head>

<body>
    <div id="sidebar">
        {% block sidebar %}
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
        {% endblock %}
    </div>

    <div id = "content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

  對標籤設置id屬性  而後{% block id屬性名字%}

 

  這個模版,咱們把它叫做 base.html, 它定義了一個能夠用於兩列排版頁面的簡單HTML骨架。「子模版」的工做是用它們的內容填充空的blocks。

  在這個例子中, block 標籤訂義了三個能夠被子模版內容填充的block。 block 告訴模版引擎: 子模版可能會覆蓋掉模版中的這些位置。

  子模版可能看起來是這樣的:

{% extends "base.html"%}

{% block title %}My amazing blog{% endblock %}
 
{% block content %}
{% for entry in blog_entries %}
    <h2>{{ entry.title }}</h2>
    <p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

  extends標籤是關鍵,他告訴模板引擎,這個模板"繼承"了另外一個模板.當模板系統處理這個模板的時候,首先,它將定位父模板----就是base.html

  

  請注意,子模版並無定義 sidebar block,因此係統使用了父模版中的值。父模版的 {% block %} 標籤中的內容老是被用做備選內容(fallback)。

  這種方式使代碼獲得最大程度的複用,而且使得添加內容到共享的內容區域更加簡單,例如,部分範圍內的導航。

  這裏是使用繼承的一些提示:

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

  • 在base模版中設置越多的 {% block %} 標籤越好。請記住,子模版沒必要定義所有父模版中的blocks,因此,你能夠在大多數blocks中填充合理的默認內容,而後,只定義你須要的那一個。多一點鉤子總比少一點好。

  • 若是你發現你本身在大量的模版中複製內容,那可能意味着你應該把內容移動到父模版中的一個 {% block %} 中。

  

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

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

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

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

六 組件

  能夠將經常使用的頁面如導航條,頁尾信息等組件保存在單獨的文件中,而後在須要使用的地方,文件的任意位置按以下語法導入便可

{% include 'navbar.html' %}

  例如:有個以下的導航欄,nav.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .c1{
            background-color: red;
            height: 40px;
        }
    </style>
</head>
<body>

<div class="c1">
    <div>
        <a href="">xx</a>
        <a href="">dd</a>
    </div>
</div>

</body>
</html>

  嵌入導航欄的頁面,test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% include 'nav.html' %}
<h1>xxxxxxxxxx</h1>
</body>
</html>  

 七 自定義標籤和過濾器

1. 在setting中的INSTALLED_APPS配置當前的app,否則django沒法找到自定義的simple_tag

2.在app中建立templatetags模塊(模塊只能是templatetags)

3.建立任意.py文件

from django import template
from django.untils.safestring import mark_safe

register = template.Library()  #register的名字是固定的,不能夠改變

@register.filter
def filter_multi(v1,v2):
    return v1*v2

@register.simple_tag  #和自定義filter相似,只不過接受更靈活的參數,沒有個數限制

def simple_tag_multi(v1,v2):
    return v1*v2

@registe.simple_tag
def my_input(id,arg):
    result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)

4. 在使用自定義simple_tag和filter的html文件中導入以前建立的my_tags.py  

{% load my_tags%}

5 使用simple_tag和filter(如何調用)

-------------------------------------------------------------.html
{% load xxx%}

#num = 12
{{ num|filter_muti:2}}    #24

{{ num|filter_multi:"[22,333,4444]"}}

{{% simple_tag_multi 2 5 %}}  參數不限,可是不能放for  和  if循環
{% simple_tag_multi num 5 %}

  注意:filter能夠用在if.for等語句後,simple_tag不能夠

{% if num|filter_multi:30 > 100 %}
    {{ num|filter_multi:30 }}
{% endif %}

  inclusion_tag

   多用於返回html代碼片斷

   示例:

    templatetags/my_inclusion.py

from django import template

register = template.Library()


@register.inclusion_tag('result.html')  #將result.html裏面的內容用下面函數的返回值渲染,
而後做爲一個組件同樣,加載到使用這個函數的html文件裏面 def show_result(n):#參數能夠傳多個進來 n = 1 if n < 1 else int(n) data = ["第{}項".format(i) for i in range(1,n+1)] return {"data":data} #這裏能夠傳多個值,和render的感受是同樣的 {'deta1':data1,
'data2':data2.....}

  templates/snippets/result.html

<ul>
  {% for choice in data %}
    <li>{{ choice }}</li>
  {% endfor %}
</ul>

  templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="x-ua-compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>inclusion_tag test</title>
</head>
<body>

{% load inclusion_tag_test %}

{% show_results 10 %}  
</body>
</html>
相關文章
相關標籤/搜索