之前有在用Django寫一些小網站,現在暑假想說再來複習一下之前買的這本書
於是我就把它寫成一系列的文章,也方便查語法
而且因為這本書大概是2014年出的,如今Django也已經出到2.多版
有些內容也變得不再支援或適用,而且語法或許也改變了
所以我會以最新版的Python和Django來修正這本書的內容跟程式碼
從這裡開始我們將以一個新的範例來做說明
請新建一個根目錄名稱為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())
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']}}
這種奇特的寫法
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:
成功讓for幫我們迭代foods裡的資料
接著要顯示第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:
整理一下各種用法
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來取得 |
如果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>
如果想要反向輸出的話,有兩種方式
{% for food in foods reversed %}
如果要同時迭代字典的鍵與值
必須這樣做
{% 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)])
在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 %}
一行的註解
{# this is comment #}
多行的註解
{% comment %}
多行註解
{% endcomment %}
過濾器(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分別顯示是、否、取消