一、模板支持的语法
Django模板中只需要记两种特殊符号:
{{ }}表示变量,在模板渲染的时候替换成值
{% %}表示逻辑相关的操作。
二、 变量(使用双大括号来引用变量)
1、语法格式:{{var_name}}
变量名由字母数字和下划线组成。
例子
urls.py文件指定url和views中的函数对应关系 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^time/$', views.localtime), ] views.py文件中编写函数,指定页面并传递字典参数 from django.shortcuts import render, HttpResponse import datetime def localtime(request): time = datetime.datetime.now() return render(request, 'time.html', {'time':time}) time.html编写html页面,通过双大括号接收字典参数 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ time }} </body> </html> 访问http://127.0.0.1:8000/time/显示时间 Feb. 15, 2019, 1:53 p.m.
locals()可以将函数中所有的变量全部传递给模板,可能会造成传递了多余的参数。
def test(request): a = 1 b = 2 c = 3 return render(request, 'test.html', locals()) #可以将a,b,c全部传递给模板
2、 深度变量的查找(万能的句点号)
上面例子中,我们传递的参数值主要是字符串,然而模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。在Django模板中遍历复杂数据结构的关键是句点字符 (.)。
urls.py和views.py中的代码不变,time.html文件修改如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>日期:{{ time.year }}年{{ time.month }}月{{ time.day }}日</p> </body> </html> 访问网页显示如下: 日期:2019年2月15日
例子2:循环显示列表中的内容
views.py def people(request): people = [ {'name':'tom', 'age':20}, {'name':'mike', 'age':21}, {'name':'jack', 'age':22}, ] return render(request, 'people.html', {'people':people}) people.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> table{ border: 1px solid black; border-spacing: 0; 300px; } table td{ border:1px solid; text-align: center; padding: 10px 0px; } </style> </head> <body> <table> <tr> <td>ID</td> <td>姓名</td> <td>年龄</td> </tr> {% for people in people %} <tr> <td>{{ forloop.counter }}</td> <td>{{ people.name }}</td> <td>{{ people.age }}</td> </tr> {% endfor %} </table> </body> </html>
访问页面结果显示:
例子3:
def template_test(request): l = [11, 22, 33] d = {"name": "alex"} class Person(object): def __init__(self, name, age): self.name = name self.age = age def dream(self): return "{} is dream...".format(self.name) Alex = Person(name="Alex", age=34) Egon = Person(name="Egon", age=9000) Eva_J = Person(name="Eva_J", age=18) person_list = [Alex, Egon, Eva_J] return render(request, "template_test.html", {"l": l, "d": d, "person_list": person_list})
模板中支持的写法:
{# 取l中的第一个参数 #}
{{ l.0 }}
{# 取字典中key的值 #}
{{ d.name }}
{# 取对象的name属性 #}
{{ person_list.0.name }}
{# .操作只能调用不带参数的方法 #}
{{ person_list.0.dream }}
注:当模板系统遇到一个(.)时,会按照如下的顺序去查询:
- 在字典中查询
- 属性或者方法
- 数字索引
3 变量的过滤器(filter)的使用
语法格式:{{obj|filter:param}}
'|'左右没有空格
value1 = 'abc' value2 = 11 value3 = [] value4 = None value5 = 'name is tom and age is 20' value6 = '姓名小明年龄20' value7 = '<a herf="#">跳转</a>' value8 = 'https://www.baidu.com/?a=1&b=2' <p>日期:{{ time.year}}年{{ time.month}}月{{ time.day}}日</p> #日期:2019年2月15日 格式化日期 <p>日期:{{ time|date:"Y年m月d日" }}</p> #日期:2019年02月15日 <p>日期:{{ time|date:"Y-m" }}</p> #日期:2019-02 字母大写 <p>{{ value1|upper }}</p> #ABC 变量值加2,如果变量是float则只显示整数部分,如果要减2,可以写成-2 <p>{{ value2|add:2 }}</p> #13 首字母大写 <p>{{ value1|capfirst }}</p> #Abc title标题 {{ value|title }} ljust左对齐 {{ value|ljust:"10" }} rjust右对齐 {{ value|rjust:"10" }} center居中 {{ value|center:"15" }} join使用字符串拼接列表。同python的str.join(list)。 {{ value |join:" // " }} 切除掉指定字符串,可以用于切掉空格 <p>{{ value1 | cut:'b' }}</p> #ac 如果值为false,则显示默认值 <p>{{ value3 | default:'值是假或空' }}</p> #值是假或空 如果值为None,则显示默认值 <p>{{ value4 | default_if_none:'值是None' }}</p> #值是None 只显示前3个单词,以空格为分隔,后面的内容显示为... <p>{{ value5 | truncatewords:3 }}</p> #name is tom ... 只显示前10个字符,后面的内容显示为...,而且这10个字符包括3个点,也就是只显示前7个字符 <p>{{ vlaue6 | truncatechars:7 }}</p> <p>{{ value7 }}</p> #<a herf="#">跳转</a> <p>去掉自动转义: {% autoescape off %} {{ value7 }} {% endautoescape %} </p> #跳转 <p>{{ value7 | safe }}</p> #跳转 <p>{{ value7 | striptags }}</p> #跳转 转成KB格式 <p>{{ value2 | filesizeformat }}</p> #11 bytes <p>第1个字符:{{ value1 | first }}</p> #a <p>最后1个字符:{{ value1 | last }}</p> #c <p>显示长度:{{ value1 | length }}</p> #3 <p>切片:{{ value1 | slice:'1::' }}</p> #bc <p>{{ value8 | urlencode }}</p> #https%3A//www.baidu.com/%3Fa%3D1%26b%3D2
三、 标签(tag)的使用(使用大括号和百分号的组合来表示tag)
语法格式: {% tags %}
1、 if elif和else的使用
if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
{% if %}标签判断一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的所有内容。
{% if num >= 100 %} {% if num > 200 %} <p>num大于200</p> {% else %} <p>num大于100小于200</p> {% endif %} {% elif num < 100%} <p>num小于100</p> {% else %} <p>num等于100</p> {% endif %}
{% if %} 标签接受and,or或者not来测试多个变量值或者否定一个给定的变量
{% if %} 标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的:{% if obj1 and obj2 or obj3 %}
2、 for的使用
{% for %}标签允许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容。
<ul> {% for obj in list %} <li>{{ obj.name }}</li> {% endfor %} </ul>
在标签里添加reversed来反序循环列表:
{% for obj in list reversed %} ... {% endfor %}
{% for %}标签可以嵌套:
{% for country in countries %} <h1>{{ country.name }}</h1> <ul> {% for city in country.city_list %} <li>{{ city }}</li> {% endfor %} </ul> {% endfor %}
系统不支持中断循环,系统也不支持continue语句,{% for %}标签内置了一个forloop模板变量,这个变量含有一些属性可以提供给你一些关于循环的信息
1)、forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1:
{% for item in todo_list %} <p>{{ forloop.counter }}: {{ item }}</p> {% endfor %}
2)、forloop.counter0 类似于forloop.counter,但它是从0开始计数,第一次循环设为0
3)、forloop.revcounter 倒序排序,最小为1
4)、forloop.revcounter0 倒序排序,最小为0
5)、forloop.first当第一次循环时值为True,在特别情况下很有用:
{% for object in objects %} {% if forloop.first %}<li class="first">{% else %}<li>{% endif %} {{ object }} </li> {% endfor %}
6)、forloop.last 当前循环是不是最后一次循环(布尔值)
7)、forloop.parentloop 本层循环的外层循环
# 富有魔力的forloop变量只能在循环中得到,当模板解析器到达{% endfor %}时forloop就消失了
# 如果你的模板context已经包含一个叫forloop的变量,Django会用{% for %}标签替代它
# 在其他非循环的地方,你的forloop变量仍然可用
3、 empty的使用
{% empty %}不需要写{% endempty %}
<ul> {% for user in user_list %} <li>{{ user.name }}</li> {% empty %} <li>空空如也</li> {% endfor %} </ul>
4、变量值乘除
{% widthratio 数 分母 分子%} {% widthratio 5 1 2%} 表示5乘以2 {% widthratio 10 2 1%} 表示10除以2
5、divisibleby value除以后面的参数,除尽为True,否则为False。可用于隔行变色
{% if value|divisibleby:"2" %} Even! {% else %} Odd! {% else %}
6、ifequal / ifnotequal
在模板语言里比较两个值可以用ifequal和ifnotequal标签
与 if 标签一样,ifequal 和 ifnotequal标签也支持else标签,但不支持elif,可以在else里面嵌套if语句。
{# 如果 a1 == a2 则显示 #} {% ifequal a1 a2 %} <h1>equal!</h1> {% else %} <h1>not equal!</h1> {% endifequal %}
首行显示红色
{% for student in students %} {% ifequal forloop.count 1%} <li style="color:red">{{student.name}}</li> {% else%} <li>{{student.name}}</li> {% endifequal %} {% endfor %}
7、 with
定义一个中间变量,用更简单的变量名替代复杂的变量名
{% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}
8、 csrf_token标签
用于生成csrf_token的标签,用于防治跨站攻击验证。 其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。
csrf豁免还有一种方式,是在函数上添加一个csrf_exempt装饰器,来实现指定某个post不需要csrf校验
@csrf_exempt def login(request): ...
9、 url
引用路由配置的地址别名
<form action="{% url "bieming"%}" > {%csrf_token%} <input type="text"> <input type="submit"value="提交"> </form>
#如果使用get请示,可以在url后面添加?get参数
<a herf="{% url 'app:user' %}?id={{ user_id }}"></a>
#如果使用post请示,可以在别名后面添加post参数
<a herf="{% url 'app:user' user_id %}"></a>
10、 verbatim
禁止render
{% verbatim %}
{{ hello }}
{% endverbatim %}
11、 注释
- 这种在前端页面的代码中是可以看到注释的,不推荐使用
<!-- 注释内容abc -->
- 2、单行注释
{# 看不到我! #}
- 多行注释
{% comment %}
看不到我!
看不到我!
看不到我!
{% endcomment %}
这两种在前端代码中是看不见的,推荐使用
12、 注意事项
1). Django的模板语言不支持连续判断,即不支持以下写法:
{% if a > b > c %}
...
{% endif %}
2). Django的模板语言中属性的优先级大于方法
def xx(request):
d = {"a": 1, "b": 2, "c": 3, "items": "100"}
return render(request, "xx.html", {"data": d})
如上,我们在使用render方法渲染一个页面的时候,传的字典d有一个key是items,并且还有默认的 d.items() 方法,此时在模板语言中:
{{ data.items }}默认会取d的items key的值100。
四、extend模板继承
到目前为止,我们的模板范例都只是些零星的 HTML 片段,但在实际应用中,你将用Django模板系统来创建整个HTML页面。 这就带来一个常见的Web开发问题:在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?Django解决此类问题的首选方法是使用一种优雅的策略—— 模板继承 。
本质上,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。
1、定义基础模板
该模板将由子模板所继承,以下是基础模板base.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> </head> <body> <h1>欢迎访问</h1> {% block content %}{% endblock %} {% block footer %} <hr> <p>Thanks for visit my site</p> {% endblock %} </body> </html>
使用模板标签: {% block %} 。 所有的 {% block %} 标签告诉模板引擎,子模板可以重载这些部分。 每个{% block %}标签所要做的是告诉模板引擎,该模板下的这一块内容将有可能被子模板覆盖。
2、继承母板
现在我们已经有了一个基本模板,我们可以通过多个子模板模板来继承它,子页面中在页面最上方使用{% extends 'base.html' %}语法来继承母板
user.html {% extends "base.html" %} {% block title %}user{% endblock %} {% block content %} <p>用户管理界面</p> {% endblock %} host.html {% extends "base.html" %} {% block title %}host{% endblock %} {% block content %} <p>主机管理界面</p> {% endblock %}
如果想进行站点级的设计修改,仅需修改 base.html ,所有其它模板会立即反映出所作修改。
3、块(block)
通过在母板中使用{% block xxx %}来定义"块"。
在子页面中通过定义母板中的block名来对应替换母板中相应的内容。
{% block page-main %} <p>世情薄</p> <p>人情恶</p> <p>雨送黄昏花易落</p> {% endblock %}
4、组件
可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。
{% include 'navbar.html' %}
以下是其工作方式:
1、在加载user.html和host.html模板时,模板引擎发现了 {% extends %} 标签, 注意到该模板是一个子模板。
2、模板引擎立即装载其父模板,即base.html。此时,base.html中的三个{% block %}标签中的内容将使用子模板的内容替换这些block。
3、由于子模板并没有定义footer块,模板系统将使用在父模板中定义的值。
使用继承的一种常见方式是下面的三层法:
<1> 创建base.html模板,在其中定义站点的主要外观,这些都是不常修改甚至从不修改的部分。
<2> 为网站的每个区域创建base_SECTION.html模板(例如, base_photos.html 和 base_form.html )。这些模板对base.html进行拓展,并包含区域特定的风格与设计。
<3> 为每种类型的页面创建独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。
这个方法可最大限度地重用代码,并使得向公共区域(如区域级的导航)添加内容成为一件轻松的工作。
以下是使用模板继承的一些诀窍:
<1>如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。
<2>一般来说,基础模板中的 {% block %} 标签越多越好。 记住,子模板不必定义父模板中所有的代码块,因此你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。 俗话说,钩子越多越好。
<3>如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。
如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。
<4>不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block标签的工作方式是双向的。
也就是说,block 标签不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。如果模板中出现了两个相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。
五、静态文件相关
settings.py文件:
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'statics'), ]
将images文件夹、mytest.js等静态文件放到创建的statics文件夹中
模板文件:
{% 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>