iT邦幫忙

0

Django學習紀錄 7.模板的變量與標籤[附常用的過濾器整理]

之前有在用Django寫一些小網站,現在暑假想說再來複習一下之前買的這本書
https://ithelp.ithome.com.tw/upload/images/20190724/20118889bj9fH1vhuR.jpg
於是我就把它寫成一系列的文章,也方便查語法
而且因為這本書大概是2014年出的,如今Django也已經出到2.多版
有些內容也變得不再支援或適用,而且語法或許也改變了
所以我會以最新版的Python和Django來修正這本書的內容跟程式碼

目錄:django系列文章-Django學習紀錄

7. 模板的變量與標籤

7.1 變量進階

從這裡開始我們將以一個新的範例來做說明
請新建一個根目錄名稱為demo的虛擬環境
demo/mysite/mysite/urls.py

from django.contrib import admin
from django.urls import path
from mysite.views import menu

urlpatterns = [
    path('admin/', admin.site.urls),
    path('menu/', menu),
]

demo/mysite/mysite/views.py

from django.shortcuts import render_to_response

def menu(request):
    food = {'name': '番茄炒蛋', 'price': 60, 'comment': '好吃', 'is_spicy': False}
    return render_to_response('menu.html', locals())

7.2 變量下層查找

demo/mysite/templates/menu.html

<!DOCTYPE html>
<html>
    <head>
        <title> Menu </title>
        <meta charset="UTF-8">
    </head>
    <body>
        <ul>
            <li> 食物的名字是: {{ food.name }}</li>
            <li> 食物的價格是: {{ food.price }}</li>
            <li> 食物說明: {{ food.comment }}</li>
            <li> 食物會辣? {{ food.is_spicy }}</li>
        </ul>
    </body>
</html>

整理一下變量的
優先序 | 變量類型 | 範例 | 在Python中的對應 | 備註
------------- | -------------
1 | 字典 | {{food.name}} | food['name'] | 字典的鍵是整數時也通,如:{{food.1}}
2 | 屬性 | {{food.bar}} | foo.bar | 在這裡bar是foo的物件屬性
3 | 方法 | {{food.bar}} | foo.bar() | 在這裡bar是foo的物件方法
4 | 清單 | {{food.0}} | food[0] | 在這裡foo是清單,譬如foo=['a','b','c']
這邊django會依序查找第一個相符的項目後便結束查詢
變量的寫法若本身有誤,會導致錯誤的頁面
但是變量往下層若無法查找則會以該便量不顯示的方式(即留白)回傳正常頁面
注意模板語言並不是python語言,所以請不要出現{{food['name']}}這種奇特的寫法

7.3 標籤

7.3.1 for 標籤

views.py

from django.shortcuts import render_to_response

def menu(request):
    food1 = {'name': '番茄炒蛋', 'price': 60, 'comment': '好吃', 'is_spicy': False}
    food2 = {'name': '蒜泥白肉', 'price': 100, 'comment': '人氣推薦', 'is_spicy': True}
    return render_to_response('menu.html', locals())

menu.html

<!DOCTYPE html>
<html>
    <head>
        <title> Menu </title>
        <meta charset="UTF-8">
    </head>
    <body>
        <h3>第1道食物</h3>
        <ul>
            <li> 食物的名字是: {{ food1.name }}</li>
            <li> 食物的價格是: {{ food1.price }}</li>
            <li> 食物說明: {{ food1.comment }}</li>
            <li> 食物會辣? {{ food1.is_spicy }}</li>
        </ul>
        <h3>第2道食物</h3>
        <ul>
            <li> 食物的名字是: {{ food2.name }}</li>
            <li> 食物的價格是: {{ food2.price }}</li>
            <li> 食物說明: {{ food2.comment }}</li>
            <li> 食物會辣? {{ food2.is_spicy }}</li>
        </ul>
    </body>
</html>

如果這裡有超級多筆資料不就慘了?
所以我們要介紹for標籤
views.py

from django.shortcuts import render_to_response

def menu(request):
    food1 = {'name': '番茄炒蛋', 'price': 60, 'comment': '好吃', 'is_spicy': False}
    food2 = {'name': '蒜泥白肉', 'price': 100, 'comment': '人氣推薦', 'is_spicy': True}
    foods = [food1, food2]
    return render_to_response('menu.html', locals())

menu.html

<!DOCTYPE html>
<html>
    <head>
        <title> Menu </title>
        <meta charset="UTF-8">
    </head>
    <body>
        {% for food in foods %}
            <ul>
                <li> 食物的名字是: {{ food.name }}</li>
                <li> 食物的價格是: {{ food.price }}</li>
                <li> 食物說明: {{ food.comment }}</li>
                <li> 食物會辣? {{ food.is_spicy }}</li>
            </ul>
        {% endfor %}
    </body>
</html>

output:
https://ithelp.ithome.com.tw/upload/images/20190715/20118889FKggRh6jNq.png
成功讓for幫我們迭代foods裡的資料

forloop變量及其屬性

接著要顯示第n道食物的標題
menu.html

<!DOCTYPE html>
<html>
    <head>
        <title> Menu </title>
        <meta charset="UTF-8">
    </head>
    <body>
        {% for food in foods %}
            <h3>第{{ forloop.counter }}道食物</h3>
            <ul>
                <li> 食物的名字是: {{ food.name }}</li>
                <li> 食物的價格是: {{ food.price }}</li>
                <li> 食物說明: {{ food.comment }}</li>
                <li> 食物會辣? {{ food.is_spicy }}</li>
            </ul>
        {% endfor %}
    </body>
</html>

output:
https://ithelp.ithome.com.tw/upload/images/20190715/201188894bZwd2e5z9.png
整理一下各種用法

forloop屬性 說明
forloop.counter 計數器,由1開始遞增到迭代總數
forloop.counter0 計數器,由0開始遞增到迭代總數
forloop.revcounter 倒數器,由迭代總數遞減到1
forloop.revcounter0 倒數器,由迭代總數遞減到0
forloop.first 若是第一次for迴圈,則為真,否則為假
forloop.last 若是最後一次for迴圈,則為真,否則為假
forloop.parentloop 父迴圈(上一層迴圈)的forloop變量
for標籤允許巢狀結構,但是如果要取用上一層的forloop變量則要使用forloop.parentloop來取得

選用的empty標籤

如果forloop所要迭代的元素量為0時
則改為輸出本區塊的內容
menu.html

<!DOCTYPE html>
<html>
    <head>
        <title> Menu </title>
        <meta charset="UTF-8">
    </head>
    <body>
        {% for food in foods %}
            <h3>第{{ forloop.counter }}道食物</h3>
            <ul>
                <li> 食物的名字是: {{ food.name }}</li>
                <li> 食物的價格是: {{ food.price }}</li>
                <li> 食物說明: {{ food.comment }}</li>
                <li> 食物會辣? {{ food.is_spicy }}</li>
            </ul>
        {% empty %}
            <p>本餐廳啥都沒賣!</p>
        {% endfor %}
    </body>
</html>

倒轉元素

如果想要反向輸出的話,有兩種方式

  1. 在視圖函式中使用清單的reverse()方法
  2. 將for標籤改為
{% for food in foods reversed %}

for標籤的限制

如果要同時迭代字典的鍵與值
必須這樣做

{% for key, value in items %}
    {{ key }} = {{ value }}
{% endfor %}}

{% for item in items %}
    {{ item.0 }} = {{ item.1 }}
{% endfor %}}

內建函式items()將字典的鍵與值分別抽出成為元組
舉例,在正常的python程式中

dic1 = {'a': 1,'b': 2}
dic2 = dic1.items()
print(dic2)

output:

dict_items([('a', 1), ('b', 2)])

7.3.2 if/elif/else 標籤

在django模板中使用if判斷式
menu.html

<!DOCTYPE html>
<html>
    <head>
        <title> Menu </title>
        <meta charset="UTF-8">
    </head>
    <body>
        {% for food in foods %}
            <h3>第{{ forloop.counter }}道食物</h3>
            <ul>
                <li> 食物的名字是: {{ food.name }}</li>
                <li> 食物的價格是: {{ food.price }}</li>
                <li> 食物說明: {{ food.comment }}</li>
                <li> 食物會辣? {% if food.is_spicy %} 辣 {% else %} 不辣 {% endif %}</li>
            </ul>
        {% empty %}
            <p>本餐廳啥都沒賣!</p>
        {% endfor %}
    </body>
</html>

也可以用elif
舉例

{% if food.is_sour %}
    酸
{% elif food.is_sweet %}
    甜
{% elif food.is_bitter %}
    苦
{% elif food.is_spicy %}
    辣
{% else %}
    沒味道
{% endif %}

7.3.3 註解與註解標籤

一行的註解

{# this is comment #}
多行的註解
{% comment %}
多行註解
{% endcomment %}

7.4 過濾器

過濾器(filter)搭配變量一起使用,利用|管道符號(pipe)可以獲取變量的資訊
如果想要顯示項目的數量(或長度)

<!DOCTYPE html>
<html>
    <head>
        <title> Menu </title>
        <meta charset="UTF-8">
    </head>
    <body>
        <p>本餐廳共有 {{ foods|length }} 道菜</p>
        {% for food in foods %}
            <h3>第{{ forloop.counter }}道食物</h3>
            <ul>
                <li> 食物的名字是: {{ food.name }}</li>
                <li> 食物的價格是: {{ food.price }}</li>
                <li> 食物說明: {{ food.comment }}</li>
                <li> 食物會辣? {% if food.is_spicy %} 辣 {% else %} 不辣 {% endif %}</li>
            </ul>
        {% empty %}
            <p>本餐廳啥都沒賣!</p>
        {% endfor %}
    </body>
</html>

過濾器也允許串連的形式,例如
{{ restaurants|first|length }}
這將會列出第一家餐廳的菜單數目
{{ word|truncatewords:"30" }}
會輸出word變量的前30個字

整理一下常用的過濾器(出自 文淵閣python架站特訓班django最強實戰 書籍p.3-18)
過濾器名稱 | 範例 | 說明
------------- | -------------
add | {{ value|add:"2" }} | 如果value=4,輸出結果6,如果value="A",輸出結果A2
addslashes | {{ value|addslashes }} | 如果value="I don\'t know",輸出結果I don\'t know
capfirst | {{ value|capfirst }} | 將value字串第一個字元轉為大寫,若字元不是字母就不處理
cut | {{ value|cut:"指定字串" }} | 移除value字串中所有指定的字串
date | {{ value|date:"D d M Y" }} | 假如為2019年7月15日15:16,顯示結果為 星期一 15 七月 2019
default | {{ value|default:"預設值" }} | 如果value是空字串,將輸出預設值
dictsort | {{ value|dictsort:"鍵" }} | 將字典依指定的鍵遞增排序
dictsortreversed | {{ value|dictsortreversed:"鍵" }} | 將字典依指定的鍵遞減排序
divisibleby | {{ value|divisibleby:"3" }} | 若value可被3整除,傳回True
escape | {{ value|escape }} | 若value中含有html標籤,html標籤將會失去作用,被視為文字輸出
filesizeformat | {{ value|filesizeformat }} | 轉成檔案大小,若value=123456789,結果為117.7MB
first | {{ value|first }} | 傳回value串列中第一個項目
join | {{ value|join:" // " }} | 將串列元素以指定字元串接,例如value=['a','b',c'],結果為a // b // c
last | {{ value|last }} | 傳回value串列中最後一個項目
length | {{ value|length }} | 傳回value串列或字串的長度,若變數未定義則傳回0
length_is | {{ value|length_is:"4" }} | 若value長度為4,傳回True
linebreaks | {{ value|linebreaks }} | 將文字內容的換行符號\n轉換為html的<br/><p></p>,例如value="I\nlove you",結果<p>I<br/>love you</p>
linebreaksbr | {{ value|linebreaksbr }} | 將文字內容的換行符號\n轉換為html的<br/>,例如value="I\nlove you",結果I<br/>love you
linenumbers | {{ value|linenumbers }} | 在文字前面加上行號,例如value="I\nlove you",結果1. I 2. love you
lower | {{ value|lower }} | 將字串轉換為小寫
upper | {{ value|upper }} | 將字串轉換為大寫
make_list | {{ value|make_list }} | 將字串轉換為串列,例如value="123",結果['1','2','3']
random | {{ value|random }} | 以亂數方式取得串列元素
safe | {{ value|safe }} | 以html格式讀取字串
slice | {{ value|slice:":2" }} | 傳回部分字串或串列,同[:2]
slugify | {{ value|slugify }} | 將字串中的空白以-取代
stringformat | {{ value|stringformat }} | 以科學記號表示,例如value=4,結果4.000000E+00
title | {{ value|title }} | value="my FIRST post",結果My First Post
truncatechars | {{ value|truncatechars:9 }} | value="Joel is a slug",結果Joel i...
wordcount | {{ value|wordcount }} | 傳回單詞數目
yesno | {{ value|yesno:"是,否,取消" }} | 依value是True False None分別顯示是、否、取消

上一篇:Django學習紀錄 6.模板初探

下一篇:Django學習紀錄 8.模型與資料庫


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言