Django之模板層

一 模板簡介

在剛剛介紹完的視圖層中咱們提到,瀏覽器發送的請求信息會轉發給視圖函數進行處理,而視圖函數在通過一系列處理後必需要有返回信息給瀏覽器。若是咱們要返回html標籤、css等數據給瀏覽器進行渲染,咱們能夠在視圖函數中這麼作css

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

上例所示,咱們直接將HTML代碼放到視圖函數裏,而後進行返回,這可使咱們很直觀地看清楚瀏覽器從發送請求到看到前端界面內容的這個過程當中視圖函數的基本工做原理,可是這種將前端代碼與後端代碼耦合到了一塊兒開發方式,會存在如下問題html

1、程序的可維護性與可擴展性問題
前端界面一旦須要從新設計、修改,則必須對後端的Python代碼進行相應的修改。 
然而前端界面的修改每每比後端 Python 代碼的修改要頻繁得多,所以若是能夠在不進行 Python 代碼修改的狀況下變動前端界面的設計,那將會方便得多。
2、開發效率問題 Python 代碼編寫和 HTML 設計是兩項不一樣的工做,大多數專業的網站開發環境都將它們分配給不一樣的人員(甚至不一樣部門)來完成。
專門的程序員去編寫 Python代碼、專門的設計人員去製做模板,這兩項工做同時進行,效率纔是最高的

基於上述緣由,將前端頁面和Python的代碼分離是一種不錯的開發模式。 爲此 Django專門提供了模板層來實現這種模式。前端

django的模板=HTML代碼+模板語法python

存放於templates目錄下的html文件稱之爲模板文件,若是咱們想要返回的html頁面中的數據是動態的,那麼必須在html頁面中嵌入變量,這便用到了django的模板語法。jquery

# 模板語法符號:
{{}} 變量相關 {%%} 邏輯相關

 模板語法之模板傳值

傳python基本數據類型

python全部的數據類型都支持傳遞給html頁面程序員

index.html數據庫

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#<p>{{ n }}</p>#}
{# 模板語法的註釋  這個註釋前端瀏覽器檢查是看不見的 #}
<!-- 瀏覽器檢查可以看到 -->
<p>{{ f }}</p>
<p>{{ s }}</p>
<p>{{ li }}</p>
<p>{{ dic }}</p>
<p>{{ t }}</p>
<p>{{ se }}</p>
<p>{{ b }}</p>
</body>
</html>

views.pydjango

def index(request):
    # python全部的數據類型都支持傳遞給html頁面
    n = 11
    f = 11.11
    s = 'hello world'
    li = [1,2,3,4,5]
    dic = {'username':'jason','password':123}
    t = (1,2,3,4,5,)
    se = {1,2,3,4,5,6}
    b = True
    # 方式一 給模板傳遞數據 (指名道姓地傳)
    # return  render(request,'index.html',{'n':n,'f':f})
    # 方式二 給模板傳遞數據
    #locals 會將當前名稱空間中全部的變量名所有傳遞給html頁面
    return render(request,'index.html',locals())

傳函數名

函數名會自動加括號執行,展現的是函數的返回值,模板語法不支持給函數傳參bootstrap

index.html後端

<p>{{ func }}</p>

views.py

def index(request):
    def func():
        print('func被執行了')
        return 'from func'
    return render(request,'index.html',locals())

傳類名和對象

傳類名,也會自動加括號實例化

index.html

<p>{{ MyClass }}</p>
<p>{{ MyClass.get_func }}</p>
<p>{{ MyClass.get_cls }}</p>
<p>{{ MyClass.get_self }}</p>
<p>{{ obj }}</p>
<p>{{ obj.get_func }}</p>
<p>{{ obj.get_self }}</p>
<p>{{ obj.get_cls }}</p>

views.py

def index(request):

    class MyClass(object):
        def get_self(self):
            return 'from self'

        @staticmethod
        def get_func():
            return 'from func'

        @classmethod
        def get_cls(cls):
            return 'from cls'
    obj = MyClass()
    return render(request,'index.html',locals())

注意:模板語法不支持傳參

取值

django模板語法取值,只有一種操做方式:句點符 .

<!--調用字符串對象的upper方法,注意不要加括號-->
<p>{{ msg.upper }}</p>

<!--取字典中k1對應的值-->
<p>{{ dic.k1 }}</p>

<!--取對象的name屬性-->
<p>{{ obj.name }}</p>

<!--取列表的第2個元素,而後變成大寫-->
<p>{{ li.1.upper }}</p>

<!--取列表的第3個元素,並取該元素的age屬性-->
<p>{{ li.2.age }}</p>

模板語法之過濾器

過濾器相似於python的內置函數,用來把視圖傳入的變量值加以修飾後再顯示

具體語法: {{ 變量名|過濾器名:傳給過濾器的參數 }}
|length
|add
|default
|truncatechars
|truncatewords
|filesizeformat
|slice
|date
|safe
#一、length 求數據的長度
# 它對字符串、列表、字典等容器類型都起做用,若是value是 ['a', 'b', 'c', 'd'],那麼輸出是4
{{ value|length }}

#二、add 加法運算
{{ 5|add:10 }}  #結果爲5+10=15
{{ 'hank'|add:'DSB' }} # 做字符串拼接'hankDSB' 

#三、default
#做用:若是一個變量值是False或者爲空,使用default後指定的默認值,不然,使用變量自己的值,若是value=’‘則輸出「nothing」
{{ value|default:"nothing" }}

#四、truncatechars
#做用:若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾,若是value=」hello world「,則輸出"hello...",注意8個字符也包含末尾的3個點
{{ value|truncatechars:8 }}

#五、truncatewords
#做用:同truncatechars,但truncatewords是按照單詞截斷,注意末尾的3個點不算做單詞,若是value=」hello world 嘎嘎「,則輸出"hello world ..."
{{ value|truncatewords:2 }}

#六、filesizeformat
#做用:將值的格式化爲一個"人類可讀的"文件尺寸(如13KB、4.1 MB、102bytes等等),若是 file_size 是 12312312321,輸出將會是 11.5 GB
{{ file_size|filesizeformat }}

#七、slice
#做用:對輸出的字符串進行切片操做,顧頭不顧尾,若是value=「hank「,則輸出"ha"
{{ value|slice:"0:2" }} 

#八、date
#做用:將日期按照指定的格式輸出,若是value=datetime.datetime.now(),按照格式Y-m-d則輸出2019-02-02
{{ value|date:"Y-m-d" }} 

#九、safe
#做用:出於安全考慮,Django的模板會對HTML標籤、JS等語法標籤進行自動轉義
{{ value|safe }}

#補充轉義:

先後端取消轉義

  前端
  |safe
  後端
  from django.utils.safestring import mark_safe
  mark_safe('<h1>安全滴</h1>')

自定義過濾器

先完成如下前期準備工做:
1.在應用名下新建一個名字必須叫templatetags文件夾
2.在該文件夾內新建一個任意名稱的py文件(eg:myfilter)
3.在該文件內 必須先寫如下兩句代碼

from django.template import Library
            
register = Library() #這裏必須叫register

演示:

index.html

{% load myfilter %}
{{ 10|my_sum:90 }}

myfilter.py

from django.template import Library

register = Library()

#自定義過濾器
@register.filter(name='my_sum')
def index(a,b):
    return a + b

模板語法之標籤

經常使用標籤之for標籤

#一、遍歷每個元素:
{% 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.counter0           當前循環的索引值(從0開始)
forloop.revcounter         當前循環的倒序索引值(從1開始)
forloop.revcounter0        當前循環的倒序索引值(從0開始)
forloop.first              當前循環是第一次循環則返回True,不然返回False
forloop.last               當前循環是最後一次循環則返回True,不然返回False
forloop.parentloop         本層循環的外層循環

#五、for標籤能夠帶有一個可選的{% empty %} 從句,在變量person_list爲空或者沒有被找到時,則執行empty子句
{% for person in person_list %}
    <p>{{ person.name }}</p>

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

{% for foo in l %}  <!--若l = [1,2,3,4,5,6]-->
    {% if forloop.first %}
        <p>這是個人第一次</p>
    {% elif forloop.last %}
        <p>這是最後一次了啊~</p>
    {% else %}
        <p>{{ foo }}</p>
    {% endif %}
    {% empty %}   <!--若l = []-->
    <p>for循環的對象內部沒有值</p>
{% endfor %}

經常使用標籤之with標籤

# with標籤用來爲一個複雜的變量名起別名,若是變量的值來自於數據庫,在起別名後只須要使用別名便可,無需每次都向數據庫發送請求來從新獲取變量的值
{% with li.1.upper as v %}
    {{ v }} #別名只能在with內使用
  #{{li.l.upper}}
{% endwith %}

經常使用標籤之if標籤

# 一、注意:
{% if 條件 %}條件爲真時if的子句纔會生效,條件也能夠是一個變量,if會對變量進行求值,在變量值爲空、或者視圖沒有爲其傳值的狀況下均爲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判斷。

自定義標籤

先完成如下前期準備工做:(和自定義過濾器同樣)
1.在應用名下新建一個名字必須叫templatetags文件夾
2.在該文件夾內新建一個任意名稱的py文件(eg:mytag)
3.在該文件內 必須先寫如下兩句代碼

from django.template import Library

register = Library()

演示:

index.html

#自定義過濾器的使用
{% load mytag %}
{% my_tag 1 2 'hello' %}

mytag.py

from django.template import Library
register = Library()

@register.simple_tag(name='my_tag')
def xxx(a,b,c):
    return '%s?%s?%s?'%(a,b,c)

#輸出結果:
1?2?'hello'

自定義標籤與自定義過濾器的區別

一、自定義過濾器只能傳兩個參數,而自定義標籤卻能夠傳多個參數

二、自定義的過濾器能夠在邏輯語句中使用,而自定義的標籤不能夠

自定義inclusion_tag

在html頁面上調用一個inclusion_tag,它會調用一個函數,這個函數把數據渲染到一個小頁面上,而後把小頁面的數據再傳給html頁面上來.

index.html

<!--自定義inclusion_tag的使用-->
{% load mytag %}
{% my 6 %}

mytag.py

from django.template import Library
register = Library()
@register.inclusion_tag('demo.html',name='my')
def index1(n):
    l = []
    for i in range(n):
        l.append(i)
    #將列表傳遞給demo.html
    return locals()

demo.html

<ul>
    {% for foo in l %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>

模板的繼承與派生之extends,block標籤

某一個頁面大部分區域都是公用的,那這個頁面就能夠做爲模板頁面.

#做用:在一個模板文件中,引入/重用另一個模板文件的內容
{% extends "模版名稱" %}
#  也就是說include有的功能extends全都有,可是extends能夠搭配一個block標籤,用於在繼承的基礎上定製新的內容

當別人繼承這個頁面以後 如何修改對應的區域的內容呢?

步驟1 先在模板頁面上經過block實現劃定區域

{% block content %}    
    模板頁面內容
{% endblock %}

步驟2 子頁面中先導入整個模板

{% extends '模板頁面.html'%}
    修改特定的區域  經過實現劃定好的區域名稱
{% block content %}
    子頁面內容
{% endblock %}

一般狀況下 模板頁面頁面應該起碼有三塊區域

{% block css %}    
模板頁面內容
{% endblock %}
{% block content %}    
模板頁面內容
{% endblock %}
{% block js %}    
模板頁面內容
{% endblock %}
# 模板的block塊越多 可擴展性越高

還支持子頁面調用父頁面對應區域的內容 而且能夠無限次調用.

若是在content裏面調,就是調用的父頁面content的內容,在css裏調,就是調用的就是父頁面css的內容

{{ block.super }}

模板的導入

在一個模板文件中,引入/重用另一個模板html文件的內容

這個html頁面一般都不是完整的,只是一個局部樣式

{% include '模版名稱' %}

關於模塊導入與繼承的實際應用案例:

url.py

 #模板的繼承
 url(r'^mb/',views.mb),
 url(r'^register/',views.register),
 url(r'^login/',views.login)

views.py

def mb(request):
    return render(request,'mb.html')

def login(request):
    return render(request,'login.html')

def register(request):
    return render(request,'register.html')
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    {% block css %}

    {% endblock %}
</head>
<body>
<nav class="navbar navbar-inverse">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Brand</a>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">Separated link</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">One more separated link</a></li>
          </ul>
        </li>
      </ul>
      <form class="navbar-form navbar-left">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Search">
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
      </form>
      <ul class="nav navbar-nav navbar-right">
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">Separated link</a></li>
          </ul>
        </li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="list-group">
              <a href="/mb/" class="list-group-item active">
                首頁
              </a>
              <a href="/register/" class="list-group-item">註冊</a>
              <a href="/login/" class="list-group-item">登陸</a>
              <a href="#" class="list-group-item">Porta ac consectetur ac</a>
              <a href="#" class="list-group-item">Vestibulum at eros</a>
            </div>
        </div>
        <div class="col-md-9">
            <div class="panel panel-primary">
              <div class="panel-heading">
                <h3 class="panel-title">Panel title</h3>
              </div>
              <div class="panel-body">
                {% block content %}
                <div class="jumbotron">
                  <h1>Hello, world!</h1>
                  <p>...</p>
                  <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
                </div>
                {% endblock %}
              </div>
            </div>
        </div>
    </div>
</div>

{% block js %}

{% endblock %}
</body>
</html>
mb.html
{% extends 'mb.html' %}

{% block css %}
    <style>
        h2  {
            color: red;
        }
    </style>
{% endblock %}

{% block content %}
    {% include 'left.html' %}

<h2 class="text-center">登陸頁面</h2>
    <form action="">
        <p>username:
            <input type="text" class="form-control">
        </p>
    <p>password:
            <input type="text" class="form-control">
        </p>
        <input type="submit" class="btn btn-primary">
    </form>
    {{ block.super }}

{% endblock %}

{% block js %}
{#    <script>#}
{#        alert(123)#}
{#    </script>#}
{% endblock %}
login.html
{% extends 'mb.html' %}

{% block css %}
    <style>
        h2  {
            color: red;
        }
    </style>
{% endblock %}

{% block content %}
    {% include 'left.html' %}

<h2 class="text-center">註冊頁面</h2>
    <form action="">
        <p>username:
            <input type="text" class="form-control">
        </p>
    <p>password:
            <input type="text" class="form-control">
        </p>
        <input type="submit" class="btn btn-danger">
    </form>
    {{ block.super }}

{% endblock %}

{% block js %}
{#    <script>#}
{#        alert(123)#}
{#    </script>#}
{% endblock %}
register.html
<p>這是一個好看的頁面組件</p>
left.html
相關文章
相關標籤/搜索