之前有在用Django写一些小网站,现在暑假想说再来複习一下之前买的这本书
于是我就把它写成一系列的文章,也方便查语法
而且因为这本书大概是2014年出的,如今Django也已经出到2.多版
有些内容也变得不再支援或适用,而且语法或许也改变了
所以我会以最新版的Python和Django来修正这本书的内容跟程式码
目录:django系列文章-Django学习纪录
7. 模板的变量与标籤
7.1 变量进阶
从这里开始我们将以一个新的範例来做说明
请新建一个根目录名称为demo的虚拟环境
demo/mysite/mysite/urls.py
from django.contrib import adminfrom django.urls import pathfrom mysite.views import menuurlpatterns = [ path('admin/', admin.site.urls), path('menu/', menu),]
demo/mysite/mysite/views.py
from django.shortcuts import render_to_responsedef 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_responsedef 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_responsedef 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里的资料
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:
整理一下各种用法
选用的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>
倒转元素
如果想要反向输出的话,有两种方式
在视图函式中使用清单的reverse()方法将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分别显示是、否、取消