1. 程式人生 > 實用技巧 >Django模板層

Django模板層

一 模板語法傳值

{{}}:變數相關

{%%}:邏輯相關

#從檢視函式的返回值中可以傳入任意型別的變數到trmplate的html的檔案中

#可以傳入函式與類
1. 傳入的函式會自動加括號呼叫 
2. 在html檔案中不能傳入引數,不然不會被識別
3. 在瀏覽器中顯示的是函式的返回值
4. 展示到html頁面中也會觸發類的__str__方法類似於列印
5. 傳入類返回到html頁面中的是類中的物件,也是相當於直接加括號呼叫例項化一個物件
6. 取列表或是字典中的單個元素只能用.的方式調用出來
	# .索引 也可以 .鍵 也能兩者混用
  
locals() 返回檢視函式中所有定義的變數到html檔案中

# 每一個web框架,都應該支援渲染模板
# 從檢視函式的返回值中傳入任意型別的變數到trmplate的html的檔案中,然後再html檔案中進行模板渲染的過程叫做DTL

過濾器

# 過濾器就類似於是模板語法內建的內建方法

# djangon內建有60多個過濾器,基本瞭解10個左右

# 基本語法
{{資料|過濾器:引數}}
變數名為 name

統計長度:{{ name |lenth }}

預設值:{{ name |default:'預設值' }} # name有值則列印這個值,沒有比如false返回預設值

file_size=123321
檔案大小: { { file_size | filesiezformat }} # 返回檔案大小自動補單位

日期格式化:{{current_time|date:'Y-m-d H:i:s'}}

切片操作: {{ name|slice:'2:4'}} 從索引2開始切到索引4
  
切取字元: { info |truncatechars:6} 包含三個點 #你好啊...
  
切取單詞: { info |truncatewords:9} 不包含三個(按照空格切,中文英文都是一樣)
  
移除特定字元:{{ info | cut:''}} 清除字串中的空格

拼接操作:{{list | join:'!'}} 列表拼接成字串

拼接操作:{{number | add:10}} 如果是數字,做數學運算  。如果是字串做拼接。如果都不是或一個數字一個															字串返回空

#重要
前端:
hhh='<h1>阿里</h1>'
取消轉義:{ { hhh }}   標籤不可被識別
可以轉義:{{hhh|safe}} 標籤可被識別

後端:
res = mark_safe('<h1>阿里</h1>') 轉義

'''
說明以後全棧專案時,前端程式碼不一定非要在前端頁面書寫
也可以先在後端寫好,然後傳遞給前端頁面
如果沒有mark_safe保護則容易遭受xss攻擊
簡單介紹 就是輸入的字串可以轉義成相關程式碼執行
那麼在前端頁面的input欄中如果輸入惡意程式碼 
後端拿到後是會儲存到資料庫中,且會被以程式碼的方式執行
那麼就會造成資料不安全的隱患
但是django內建的mark_safe就解決了這個問題
'''

標籤

# for 迴圈
{% for li in lis %}
    <p>{{ forloop }}</p>
  	<p>{{ li }}</p>

{% endfor %}

# 列印了每次迴圈時當時變數的內建屬性
	-1.counter0:從0開始,每迴圈一次加1
	-2.counter: 從1開始,每迴圈一次加1
	-3.revcounter:從整體的長度開始,每迴圈一次減1一直到1(倒數)
  -4.revcounter0:從最大的索引開始,每迴圈一次減1一直到0
  -5.first:判斷是不是迴圈的第一個
  -6.last: 判斷是不是迴圈的最後一個
  -7.parentloop:父級forloop物件(for迴圈巢狀)
{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 6, 'revcounter0': 5, 'first': True, 'last': False}

{'parentloop': {}, 'counter0': 1, 'counter': 2, 'revcounter': 5, 'revcounter0': 4, 'first': False, 'last': False}

{'parentloop': {}, 'counter0': 2, 'counter': 3, 'revcounter': 4, 'revcounter0': 3, 'first': False, 'last': False}

{'parentloop': {}, 'counter0': 3, 'counter': 4, 'revcounter': 3, 'revcounter0': 2, 'first': False, 'last': False}

{'parentloop': {}, 'counter0': 4, 'counter': 5, 'revcounter': 2, 'revcounter0': 1, 'first': False, 'last': False}

{'parentloop': {}, 'counter0': 5, 'counter': 6, 'revcounter': 1, 'revcounter0': 0, 'first': False, 'last': True}

# if 判斷
{% if flag %}

    <script>
        alert('重新輸入')
    </script>
{% else %}
    <script>
        alert('登入成功')
    </script>
{% endif %}

# 兩者混用
{% for li in lis %}
    {% if forloop.first %}
        <p>這是我第一次</p>
    {% elif forloop.last %}
        <p>這是我最後一次</p>
    {% else %}
        <p>{{ li }}</p>

    {% endif %}
    {% empty %}
        <p> for迴圈的迭代物件為空 </p> #不代表迴圈物件迭代完就能觸發

{% endfor %}

# 起別名
{% with dic.hobby.3 as name %}
		<p>{{name}}</p>
{% enwith %}

# csrf標籤(瞭解)

自定義標籤和過濾器

# 自定義標籤

	-1.在setting中的INSTALLED_APPS配置當前app,不然Django無法找到自定義的simple_tag
  -2.在app中建立templatetags包 # 注意:包名只能是templatetags,不能改
  -3.在包內,新建py檔案 # 如:my_tags.py
  -4.寫過濾器的邏輯程式碼
      from django import template
      register = template.Library()
      @register.filter
      def my_upper(values):
          return values.upper()
  -5.渲染模板,先load,再使用
  		<p>內建的過濾器:{{ 'abab'|upper }}</p>

      {% load my_tag %}

      <p>自定義的過濾器:{{ 'abab'|my_upper }}</p>
      

# 自定義標籤
	-1.在setting中的INSTALLED_APPS配置當前app,不然Django無法找到自定義的simple_tag
  -2.在app中建立templatetags包 # 注意:包名只能是templatetags,不能改
  -3.在包內,新建py檔案 # 如:my_tags.py
  -4.寫過濾器的邏輯程式碼
  	from django import template
		from django.utils.html import mark_safe

		register = template.Library()
    @register.simple_tag
    def my_csrf():
        import uuid
        res = uuid.uuid4()
        return mark_safe('<input type="hidden" name="csrfmiddlewaretoken" 				      value="%s">' % res)
   -5.渲染模板,先load,在使用
  {% csrf_token %}

	{% my_csrf %}
  '''
  內建標籤在瀏覽器顯示:<input type="hidden" name="csrfmiddlewaretoken" value="ZefILcDWtxMlSb2mhS8bGbtscpnYRiJuctBGWRwGC7DMC0rZ3xLFwBznexljvKFI">
  自定義標籤在瀏覽器顯示:<input type="hidden" name="csrfmiddlewaretoken" value="d39fd1ad-ba68-4123-af4b-82f5969bba1d">
  '''

二 模板的繼承

'''
有些網站的頁面整體大差不差 風格形式相同 只是某一些區域性在變化
'''

# 模板的繼承  你自己先選好一個你想要繼承的模板頁面
{% entends 'home.html' %}

# 繼承了之後頁面跟模板頁面長得一模一樣,需要在模板頁面上劃定可以被修改的區域
{% block content %}
   模板內容
{% endblock %}

# 子頁面就可以宣告想要修改的劃定了的區域

{% block content %}
	子頁面內容
{% endblock %}

# 一般情況下模板頁面上應該至少有三塊可以被修改的區域
		1.css區域
  	2.html區域
    3.js區域
    
# 作用:每個子頁面都可以有自己獨有的css程式碼、html程式碼、js程式碼

'''
一般情況下 模板的頁面劃定的區域越多 擴充套件性越高
但是如果太多 不如自己寫
'''


三 模板的匯入

'''
將頁面的某一個區域性當成模組的形式
哪個地方需要就可以直接匯入即可
'''
	-第一步:新建一個 xx.html,把好看的模板寫入
        <div class="panel panel-danger">
            <div class="panel-heading">
                <h3 class="panel-title">重金求子</h3>
            </div>
            <div class="panel-body">
                詳情點選:<a href="http://www.baidu.com">瘋狂點我</a>
            </div>
        </div>
  -第二步:再你想用的地方
    	{% include 'xx.html' %}

四 前後端互動編碼方式

1.urlencoded----->傳普通的資料,form表單預設就是這種----->request.POST
2.form-data------>傳檔案和資料									 ----->request.POST request.FILES
3.json----------->傳json格式資料								 ------>request.body 反序列化處理

def index(request):
  	# 接收urlencoded編碼
    body體中:name = lqz&age = 18
    # print(request.POST) 最好通過此方式獲得資料
      
     # 接收form-data編碼
    body體中:分兩部分,一部分是資料,一部分是檔案
    資料部分:name=lqz&age=18
    -------------------------
    檔案部分(二進位制)
    
    # 資料部分
    # print(request.POST)
    # #檔案部分
    # print(request.FILES)

    # 接收json格式
    body體中 
    {
    "name": "lqz",
    "age": 18
	}
    # 這裡沒有
    print(request.POST)
    # 資料在這(自行處理)
    print(request.body)


    return HttpResponse('ok')

五 靜態檔案相關

# 三種方式
# 如:在html檔案中匯入本地的bootstrap的樣式
	第一種:
  <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">

	第二種:
  {% load static %}
   <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
	相當於先找到了配置檔案setting.py 中的 STATIC_URL = '/static/'
  那麼是動態的匯入模組,比如就算 STATIC_URL = '/aaaa/' 改成這樣子 也能成功匯入
  
  第三種:
   {% load static %}
	<link rel="stylesheet" href="{% get_static_prefix %}bootstrap/css/bootstrap.min.css">

# 推薦使用第二種
  
# 特殊用法
# 如果匯入檔案的檔名過長,如圖片檔案,且之後要重複使用,那可以在第一次匯入時取別名
   {% load static %}
    <img src="{% static '1036857-20180821192355156-1472752634.png' as myphotor%}" alt="">
    <img src="{{ myphotor }}" alt="">
    <img src="{{ myphotor }}" alt="">
    <img src="{{ myphotor }}" alt="">
    <img src="{{ myphotor }}" alt="">
  

六 inclusion_tag的使用

# 可以生成一片模板中的程式碼塊
# 使用:6步

-第一步:在settings中的INSTALLED_APPS配置當前app,不然django無法找到自定義的simple_tag
-第二步:在app中建立templatetags包(包名只能是templatetags,不能改)
-第三步:在包內,新建py檔案(如:my_tags.py)
-第四步:寫程式碼(inclusion_tag)
				@register.inclusion_tag('flag.html')  # 在此html檔案中進行渲染
        def flag(num):
            dic = {i: '第%s頁' % i for i in range(num)}
            # 固定返回的必須是字典
            print(dic)
            return {'dic': dic}
-第五步:在定義的第三方模板進行渲染
					<ul>

            {% for k,v in dic.items %}
                <li>{{ v }}</li>

            {% endfor %}

					</ul>
-第六步:在需要返回到瀏覽器的模板中,動態的匯入已經在第三方渲染好的模板
			{% load my_tag %}
    	{% flag 10 %}     # 傳入引數匯入10個頁面
    # 相比一般的include匯入模板,這樣的自定義可以傳參具有更高的延展性
    
# 它跟tag有什麼不同?
	-tag需要再程式碼中寫html的東西
  		返回時需要mark_safe一個html檔案的內容,造成了程式碼的冗餘
  -inclusion_tag程式碼跟模板分離   
  		通過@register.inclusion_tag('flag.html')選擇一個第三方模板將資料在此模板渲染好了
    	再匯入需要此模板的html檔案中(解耦合)

七 練習

# 在請求頭中建立頭data 在其中可以取urlencoded,form-data,json這三種編碼格式的資料

# 寫一個裝飾器

def data(func):
    def wrapper(request, *args, **kwargs):
        import json
        try:
            # 如果能夠正常反序列化說明是Json格式,然後放入請求頭data中
            # 如果不是則觸發異常捕獲
            obj = json.loads(request.body)
            request.data = obj
        except Exception as e:
            # 這時已經說明肯定是其他編碼格式(urlencoded,form-data)
            obj = request.POST
            # 直接新增
            request.data = obj
        res = func(request, *args, **kwargs)  # request請求作為已知必須的傳入的引數可以單獨拿出來
        return res

    return wrapper
  
@data
def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    else:
        name = request.data.get('name')   # 可直接從請求頭data中取資料
        pwd = request.data.get('password')
        all_info = models.UserInfo.objects.all()
        for user in all_info:
            if name == user.name and pwd == user.password:
                return HttpResponse('successful')
        else:
            return render(request, 'login.html', {'flag': True})
# 在響應體中新增請求頭

def home(request):
    obj = render(request, 'home.html', {'flag': 'abab'})
    obj['name'] = 'arther'
    obj['age'] = 18
    return obj

# 瀏覽器終端顯示

age: 18
Content-Length: 1392
Content-Type: text/html; charset=utf-8
Date: Mon, 12 Oct 2020 09:21:05 GMT
name: arther
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.8.4
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
# 遮蔽敏感詞彙

def work(request):
    if request.method == 'GET':
      # 通過GET請求的方式先返回一個輸入文字框的頁面
        return render(request, 'work.html')
    import re
    name = request.POST.get('name')
    obj = re.findall('.*?(草你媽|傻逼|狗子|你媽)', name)
    # 正則中的分組每次只能返回一個匹配內容,通過.*?的方式匹配完字串所有的內容,匹配到一個內容後不會再重頭,而是繼續匹配分組內的其他字元,並以列表的方式儲存
    # 通過正則匹配將輸入的內容中的敏感詞彙放入列表
    if obj:
        for i in obj:
            if i in name:
              # 得到敏感詞彙的長度
                data = len(i)
                name = name.replace(i, '*' * data)
    return HttpResponse(name)