Django之模板層

Django之模板層

在例子視圖中返回文本的方式有點特別,即HTML被直接硬編碼在Python代碼之中。css

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

儘管這種技術便於解釋視圖是如何工做的,但直接將HTML硬編碼到你的視圖裏卻並是一個好主意。讓咱們來看一下爲何:html

  • 對頁面設計進行的任何改變都必須對Python代碼進行相應的修改。站點設計的修改每每比底層Python代碼的修改要頻繁得多,所以若是能夠在不進行Python代碼修改的狀況下變動設計,將會方便不少。
  • Python代碼編寫和HTML設計是兩項不一樣的工做,大多數專業的網站開發環境都將他們分配給不一樣的人員(甚至不一樣的部門)來完成。設計者和HTML/CSS的編碼人員不該該被要求去編輯Python的代碼來完成他們的工做。
  • 程序員編寫Python代碼和設計人員製做模板兩項工做過同時進行的額效率是最高的,遠勝於讓一我的等待另外一我的完成對某個既包含Python又包含HTML的文件的編輯工做。

基於這些緣由,將頁面的設計和Python的代碼分離開會更乾淨簡潔更容易維護。咱們可使用Django的模板系統(Template System)來是如今這種模式,這就是本章要具體討論的問題。python

Python的模板:HTML代碼 + 模板語法程序員

def current_time(req):
    # ================================原始的視圖函數
    # import datetime
    # now=datetime.datetime.now()
    # html="<html><body>如今時刻:<h1>%s.</h1></body></html>" %now

    # ================================django模板修改的視圖函數
    # from django.template import Template,Context
    # now=datetime.datetime.now()
    # t=Template('<html><body>如今時刻是:<h1>{{current_date}}</h1></body></html>')
    # #t=get_template('current_datetime.html')
    # c=Context({'current_date':str(now)})
    # html=t.render(c)
    #
    # return HttpResponse(html)

    #另外一種寫法(推薦)
    import datetime
    now=datetime.datetime.now()
    return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})

1、模板語法之變量

在Django模板中遍歷複雜數據結構的關鍵是句點字符,語法:數據庫

{{var_name}}

views.py:django

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

    person_yuan=Person("yuan")  # 自定義類對象
    person_egon=Person("egon")
    person_alex=Person("alex")

    person_list=[person_yuan,person_egon,person_alex]

     return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list})

template:緩存

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

注:句點符也能夠用來引用對象的方法(無參數方法):安全

<h4>字典:{{ dic.name.upper }}</h4>

2、模板之過濾器

語法:數據結構

{{obj|filter_name:param}}

defaultapp

若是一個變量是False後者爲空,使用給定的默認值。不然,使用變量的值。例如:

{{ value|default:'nothing' }}

length

返回值的長度。它對字符串和列表都起做用。例如:

{{ value|length }}

若是value是['a', 'b', 'c', 'd'],那麼輸出的就是4.

filesizeformat

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

{{ value|filesizeformat }}

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

date

若是value = datetime.datetime.now()

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

slice

若是value = "hello world"

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

truncatechars

若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列("...")結尾。

參數:要截斷的字符數

{{ value|truncatechars:9 }}

safe

Django的模板中會對HTML標籤和JS語法等標籤進行自動轉義,緣由顯而易見這樣是爲了安全。可是有時候咱們可能不但願這些HTML元素被轉義,好比咱們作一個內容管理系統,後他添加的文章中是通過修飾的,這些修飾多是經過一個相似於FCKeditor編輯加註了HTML修飾符的文本,若是自動轉義的話顯示的就是保護HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,若是是一個單獨的變量咱們能夠經過過濾器"|safe"的方式告訴Django這段代碼是安全的沒必要轉義。好比:

value = "<a href=''>點擊</a>"
{{ value|safe }}

3、模板之標籤

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

for標籤

遍歷每個元素:

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

遍歷一個字典:

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

注:循環序號能夠經過{{ for|loop }}顯示

forloop.counter           # The current iteration of the loop (1-indexed)
forloop.counter0          # The current iteration of the loop (0-indexed)
forloop.revcounter        # The number of iterations from the end of the loop (1-indexed)
forloop.revcounter0       # The number of iterations from the end of the loop (0-indexed)
forloop.first             # True if this is the first time through the loop
forloop.last              # True if this is the last time through the loop

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 %}
    <p>湊活吧</p>
{% endif %}

with 標籤

使用一個簡單地名字緩存一個複雜的變量,當你須要使用一個「昂貴」的方法(好比訪問數據庫)不少次的時候是很是有用的。例如:

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

csrf_token 標籤

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

4、自定義標籤和過濾器

一、在settings中的INSTALLED_APPS配置當前app,否則Django沒法找到自定義的simple_tag。

二、在app中建立templatetags模塊(模塊名只能是templatetags)。

三、建立任意 .py 文件,如:my_tags.py。

from django import template
  from django.utils.safestring import mark_safe
  register = template.Library()   #register的名字是固定的,不可改變  
  @register.filter
  def filter_multi(v1,v2):
      return  v1 * v2

  @register.simple_tag
  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)

四、在使用自定義simple_tag和filter的HTML文件中導入以前建立的my_tags.py。

{% load my_tags %}

五、使用simple_tag和filter(如何調用)

-------------------------------.html
  {% load xxx %}        
  # num=12
  {{ num|filter_multi:2 }} #24
  {{ num|filter_multi:"[22,333,4444]" }}
  {% simple_tag_multi 2 5 %}  參數不限,但不能放在if for語句中
  {% simple_tag_multi num 5 %}

注:filter能夠用在if等語句後,simpe_tag不能夠。

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

5、模板繼承(extend)

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

經過從下面這個例子開始,能夠容易地理解模板繼承:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}My amazing site{% 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>

假設這個模板叫作 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。

那時,模板引擎將注意到 base.html 中的三個block標籤,並用子模板中的內容來替換這些block。根據blog_entries的值,輸出可能看起來是這樣的:

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>My amazing blog</title>
</head>

<body>
    <div id="sidebar">
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
    </div>

    <div id="content">
        <h2>Entry one</h2>
        <p>This is my first entry.</p>

        <h2>Entry two</h2>
        <p>This is my second entry.</p>
    </div>
</body>
</html>

請注意,子模版並無定義 sidebar block,因此係統使用了父模版中的值。父模版的 {% block %} 標籤中的內容老是被用做備選內容(fallback)。這種方式使代碼獲得最大程度的複用,而且使得添加內容到共享的內容區域更加簡單,例如,部分範圍內的導航。

下面是使用繼承的一些提示:

  • 若是你在模版中使用 {% extends %} 標籤,它必須是模版中的第一個標籤。其餘的任何狀況下,模版繼承都將沒法工做。
  • 在base模版中設置越多的 {% block %} 標籤越好。請記住,子模版沒必要定義所有父模版中的blocks,因此,你能夠在大多數blocks中填充合理的默認內容,而後,只定義你須要的那一個。多一點鉤子總比少一點好。
  • 若是你發現你本身在大量的模版中複製內容,那可能意味着你應該把內容移動到父模版中的一個 {% block %} 中。
  • If you need to get the content of the block from the parent template, the variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template.
  • 爲了更好的可讀性,你也能夠給你的{% endblock %} 標籤一個 名字 。例如:
{% block content %}
...
{% endblock content %}

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

  • 不能在一個模版中定義多個相同名字的 block 標籤。
相關文章
相關標籤/搜索