Django基礎四之模板系統

Django基礎四之模板系統

一 語法

模板渲染的官方文檔css

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

  • {{ }}和 {% %}
  • 變量相關的用{{}},邏輯相關的用{%%}。

二 變量

在Django的模板語言中按此語法使用:{{ 變量名 }}。前端

  當模版引擎遇到一個變量,它將計算這個變量,而後用結果替換掉它自己。 變量的命名包括任何字母數字以及下劃線 ("_")的組合。 變量名稱中不能有空格或標點符號。python

  深度查詢據點符(.)在模板語言中有特殊的含義。當模版系統遇到點("."),它將以這樣的順序查詢:數據庫

    字典查詢(Dictionary lookup)
    屬性或方法查詢(Attribute or method lookup)
    數字索引查詢(Numeric index lookup)django

  注意事項:bootstrap

  1. 若是計算結果的值是可調用的,它將被無參數的調用。 調用的結果將成爲模版的值。
  2. 若是使用的變量不存在, 模版系統將插入 string_if_invalid 選項的值, 它被默認設置爲'' (空字符串) 。

  幾個例子:後端

  view中代碼:瀏覽器

from django.shortcuts import render


# Create your views here.
def index(request):
   num = 100
   name = 'anwen'
   lst = ['安文', 'didi']
   # lst=[]

   dic = {'name': '安文', 'age': 23, 'hobby': '游泳'}

   class Animal():
      def __init__(self):
         self.kind = 'dog'

      def eat(self):
         return 'chi'

   a = Animal()
   # xx='ll'

   filesize = '432511234.234'

   words = 'hello word i have a dream'

   tag = '<a href="http://www.baidu.com">百度</a>'
   import datetime
   time = datetime.datetime.now()

   # return render(request,'index.html',{'num':num,'name':name,'lst':lst,'dic':dic})
   print(locals())
   return render(request, 'index.html', locals())

模板index中支持的寫法:緩存

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>數字:{{ num }}</p>
<p>字符串:{{ name }}</p>
<p>列表:{{ lst }}</p>
<p>{{ lst.2 }}</p>
<p>字典:{{ dic }}</p>
<p>{{ dic.name }}</p>
<p>類方法:{{ a.eat }}</p>
</body>
</html>

三 過濾器

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

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

  使用管道符"|"來應用過濾器。

  例如:{{ name|lower }}會將name變量應用lower過濾器以後再顯示它的值。lower在這裏的做用是將文本全都變成小寫。

  注意事項:

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

  Django的模板語言中提供了大約六十個內置過濾器。

default

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

<p>{{ xx|default:'啥都沒有' }}</p>  #若是value沒有傳值或者值爲空的話就顯示啥都沒有

length

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

    {{ value|length }}

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

{#獲取數據長度#}
<p>{{ lst|length }}</p>

filesizeformat

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

filesize = '432511234.234'
<p>{{ filesize|filesizeformat }}</p>    #若是filesize是432511234.234,輸出將會是412.5 MB

slice

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

{#切片,若是 value="hello world",還有其餘可切片的數據類型#}
<p>{{ words|slice:'6:10' }}</p>

date

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

{{ value|date:"Y-m-d H:i:s"}}
關於時間日期的可用的參數(除了Y,m,d等等)還有不少,有興趣的能夠去查查看看。

truncatechars

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

    參數:截斷的字符數

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

truncatewords

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

    例如:‘hello word i have a dream’,

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

cut

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

hello word i have a dream
{{ value|cut:' ' }}     #hellowordihaveadream

join

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

lst = ['安文', 'didi','yage']
<p>{{ lst|join:'+' }}</p>   #安文+didi+yage

四 標籤Tags

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

for標籤

    遍歷每個元素: 寫個for,而後 tab鍵自動生成for循環的結構,循環很基礎,就這麼簡單的用,沒有什麼break之類的,複雜一些的功能,你要經過js

{% for l in lst %}
    <p>{{ forloop.counter }}{{ l }}</p> <!--凡是變量都要用兩個大括號括起來-->
<!--for ... empty-->
<!--for 標籤帶有一個可選的{% empty %} 從句,以便在給出的組是空的或者沒有被找到時,能夠有所操做。-->
{% empty %}
    <p>no</p>
{% endfor %}

{#遍歷一個字典#}
{% for key,value in dic.items %}
    <p>{{ key }}--{{ value }}</p>
{% endfor %}

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

forloop.counter            當前循環的索引值(從1開始),forloop是循環器,經過點來使用功能
forloop.counter0           當前循環的索引值(從0開始)
forloop.revcounter         當前循環的倒序索引值(從1開始)
forloop.revcounter0        當前循環的倒序索引值(從0開始)
forloop.first              當前循環是否是第一次循環(布爾值)
forloop.last               當前循環是否是最後一次循環(布爾值)
forloop.parentloop         本層循環的外層循環的對象,再經過上面的幾個屬性來顯示外層循環的計數等

if 標籤

    {% if %}會對一個變量求值,若是它的值是「True」(存在、不爲空、且不是boolean類型的false值),對應的內容塊會輸出。if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷,注意條件兩邊都有空格。

{% if num > 100 %}
    <p>大於100</p>
{% elif num < 100 %}
    <p>小於100</p>
{% else %}
    <p>等於100</p>
{% endif %}
{#Django的模板語言不支持連續判斷,即不支持如下寫法:#}
{#{% if a > b > c %}#}
{#...#}
{#{% endif %}#}

with

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

    例如:

    注意等號左右不要加空格。

{% with dic.hobby as hb %}
    <p>{{ hb }}</p>
{% endwith %}

{#注意:等號左右不要加空格。#}
{% with hb=dic.hobby  %}
    <p>{{ hb }}</p>
{% endwith %}

csrf_token

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

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

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

    爬蟲發送post請求簡單模擬:

import requests

res = requests.post('http://127.0.0.1:8000/login/',data={
    'username':'chao',
    'password':'123'
})

print(res.text)

csrf_token繞過csrf的防護機制

#views.py
from django.shortcuts import render
def token(request):
   return render(request, 'token.html')
<!--token.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>token</title>
</head>
<body>
<form action="" method="post">
    {% csrf_token %}

    用戶名: <input type="text" name="username">
    <button>提交</button>
</form>
</body>
</html>

五 模板繼承

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

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 模板
    url(r'^base/', views.base),
    url(r'^menu1/', views.menu1),
    url(r'^menu2/', views.menu2),
    url(r'^menu3/', views.menu3),
]
#views.py
from django.shortcuts import render
def base(request):  #模板函數
   return render(request, 'base.html')  #模板頁面
def menu1(request):
   return render(request, 'menu1.html')
def menu2(request):
   return render(request, 'menu2.html')
def menu3(request):
   return render(request, 'menu3.html')
<!--menu1.html-->
{% extends 'base.html' %}
{% block content %}
    menu1
{% endblock %}

<!--menu2.html-->
{% extends 'base.html' %}
{% block content %}
    menu2   
{% endblock %}

<!--menu3.html-->
{% extends 'base.html' %}
{% block content %}
    menu3   
{% endblock %}

六 組件

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

{% include 'navbar.html' %}
#urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 組件nav
    url(r'^nav/', views.nav),
    url(r'^newnav/', views.nav),
]
#views.py
from django.shortcuts import render
def nav(request):
   return render(request,'nav.html')
def newnav(request):
   return render(request,'newnav.html')

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

<!--nav.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>nav</title>
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        .nav {
            background: red;
            height: 40px;
        }
    </style>
</head>
<body>

<div class="nav">
    <a href="">導航</a>
    <a href="">導航</a>
    <a href="">導航</a>
    <a href="">導航</a>
    <input type="text">
    <button>搜索</button>
</div>
</body>
</html>

用了組件的newnav.html

<!--newnav.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{# 組件#}
{#能夠將經常使用的頁面內容如導航條,頁尾信息等組件保存在單獨的文件中,而後在須要使用的地方,文件的任意位置按以下語法導入便可。#}
{% include 'nav.html' %}
</body>
</html>

組件和插件的簡單區別

組件是提供某一完整功能的模塊,如:編輯器組件,QQ空間提供的關注組件 等。
而插件更傾向封閉某一功能方法的函數。
這二者的區別在 Javascript 裏區別很小,組件這個名詞用得很少,通常統稱插件。

自定義標籤和過濾器

自定義過濾器

1. app應用文件夾中建立一個templatetags文件件,必須是這個名字
2. templatetags文件夾中建立一個 filtertest.py文件,文件名字隨便起
3. 建立自定義過濾器
    from django import template
    # register的名字是固定的,不可改變,註冊器
    register = template.Library()

    # @register.filter
    # def filter(v1):   #一個參數
    #   v = v1 + 'yage'
    #   return v

    @register.filter
    def filter(v1, v2):  # 兩個參數
        v = v1 + 'yage' + v2
        return v

4. 使用  html文件中  {% load 文件名 %} 
    {% load filtertest %}
    {#一個參數#}
    {{ v1|filter }}

    {#兩個參數#}
    {{ v1|filter:' nihao' }}

5. 注意:# filter參數有限制,最多兩個參數

自定義標籤

1. app應用文件夾中建立一個templatetags文件件,必須是這個名字
2. templatetags文件夾中建立一個 xx.py文件,文件名字隨便起
3. 建立自定義標籤
    from django import template
    # register的名字是固定的,不可改變,註冊器
    register = template.Library()
    # simple_tag和自定義filter相似,只不過接收更靈活的參數,沒有個數限制。
    # 注意:filter能夠用在if、for等語句後,simple_tag不能夠
    @register.simple_tag
    def simple_tag(vv):
        v = 'yagehaha' + vv
        return v
4. 使用  html文件中  {% load 文件名 %} 
    {#simple_tag標籤#}
    <p>{% simple_tag v1 %}</p>
5. #能夠傳多個參數

inclusion_tag

1. app應用文件夾中建立一個templatetags文件件,必須是這個名字
2. templatetags文件夾中建立一個 xx.py文件,文件名字隨便起
3. 建立自定義inclusion_tag
    # 多用於返回html代碼片斷  做爲一個組件
    @register.inclusion_tag('inclusion_tag.html')
    # 將inclusion_tag.html裏面的內容用下面函數的返回值渲染,而後做爲一個組件同樣,加載到使用這個函數的html文件裏面
    def inclusion_tag(ll):  # 參數能夠傳多個進來
        return {'date': ll}  
    # 這裏能夠穿多個值,和render的感受是同樣的{'data1':data1,'data2':data2....}

# views 的 ll 傳給 index.html 中的{% inclusion_tag ll%},
# inclusion_tag 接收參數到filtertest.py 的 def inclusion_tag(ll),
# 將參數ll傳給@register.inclusion_tag('inclusion_tag.html') 進行模板渲染。
4.使用
    {% inclusion_tag ll%}

靜態文件配置

js、css、img等都叫作靜態文件,那麼關於django中靜態文件的配置,咱們就須要在settings配置文件裏面寫上這寫內容:

1 在項目中建立一個文件夾,好比叫jingtaiwenjian

# STATIC_URL = '/xxx/' #別名,隨便寫名字,可是若是你更名字,別忘了前面頁面裏面若是你是經過/xxx/bootstrap.css的時候,若是這裏的別名你改爲了/static/的話,你前端頁面的路徑要改爲/static/bootstrap.css。因此咱們都是用下面的load static的方式來使用靜態文件路徑
2 STATIC_URL = '/static/' #別名

3 STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'jingtaiwenjian'), #注意別忘了寫逗號,第二個參數就是項目中你存放靜態文件的文件夾名稱
]

目錄:別名也是一種安全機制,瀏覽器上經過調試臺你可以看到的是別名的名字,這樣別人就不能知道你靜態文件夾的名字了,否則別人就能經過這個文件夾路徑進行攻擊。

前端頁面引入靜態文件的寫法,由於別名也可能會修改,因此使用路徑的時候經過load static來找到別名,經過別名映射路徑的方式來獲取靜態文件

{% static %}

{% 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>

{% get_static_prefix %}

{% load static %}
<img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" />

或者
{% load static %}
{% get_static_prefix as STATIC_PREFIX %}

<img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" />
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />
相關文章
相關標籤/搜索