django模版层
django模版层功能:接收视图层传过来的数据,渲染到html模版文件。
此外,还支持模版文件的继承和导入,减少模版文件代码的重复书写。
模版语法
模版语法有两个:{{ }}
和 {% %}
# {{ }}
变量相关; 用在:传值、过滤器、自定义过滤器filter
# {% %}
逻辑相关; 用在:标签(if判断 for循环)、自定义标签simple_tag、inclusion_tag、模版继承extend和导入include
模版语法传值
传值使用的模板语法是:{{ }}
传值的类型:python基本数据类型、函数、类、对象等
注意点:
-
变量传值时,既支持python基本的数据类型,还支持函数、类和对象。
-
如果传递的是函数名,则渲染函数的返回值,且此时函数不能有形参(否则,不做任何处理)。
-
如果传递的是类名,则会直接实例化一个对象,在前端页面打印该对象。
-
如果传递的是已经实例化后的对象,如果该对象有
__call__
方法,则优先执行__call__
里面的返回值;如果没有该方法,则再直接打印该对象。 -
打印对象时,如果对象有
__str__
方法,则返回该方法的返回值。 -
django模版语法的取值,是固定的格式,只能采用“句点符”
.
-
即可以点键也可以点索引,还可以两者混用。
<p>{{ d.username }}</p> # 字典使用点key方式
<p>{{ l.0 }}</p> # 列表使用点索引的方式
<p>{{ obj.get_class }}</p> # 对象点属性或方法的方式
过滤器
过滤器:类似于是模版语法内置的内置方法;
基本语法:{{数据|过滤器:参数}}
,其中参数是可选的(不需要参数的过滤器不是用参数功能)。
注意:过滤器最多接收两个参数:管道符号前一个,管道符后面一个,如:{{ current_time|date:'Y-m-d H:i:s' }}
补充:过滤器safe
比较实用,可以起到保护页面的作用,
# 前端
<p>转义:{{ sss|safe }}</p>
# 后端
from django.utils.safestring import mark_safe
res = mark_safe('<h1>新新</h1>')
常用过滤器
<p>统计长度:{{ s|length }}</p>
<p>默认值(第一个参数布尔值是True就展示第一个参数的值否在展示冒号后面的值):{{ b|default:'啥也不是' }}</p>
<p>文件大小:{{ file_size|filesizeformat }}</p>
<p>日期格式化:{{ current_time|date:'Y-m-d H:i:s' }}</p>
<p>切片操作(支持步长,负步长):{{ l|slice:'0:4:2' }}</p>
<p>切取字符(包含三个点):{{ info|truncatechars:9 }}</p>
<p>切取单词(不包含三个点 按照空格切):{{ egl|truncatewords:9 }}</p>
<p>切取单词(不包含三个点 按照空格切):{{ info|truncatewords:9 }}</p>
<p>移除特定的字符:{{ msg|cut:' ' }}</p>
<p>拼接操作:{{ l|join:'$' }}</p>
<p>拼接操作(数字时加法操作):{{ n|add:10 }}</p>
<p>拼接操作(字符串拼接):{{ s|add:msg }}</p>
<p>转义:{{ hhh|safe }}</p>
<p>转义:{{ sss|safe }}</p>
<p>转义:{{ res }}</p>
标签
for循环
{% for item in li %}
<p>{{ forloop.counter }}, {{item}}</p> # 循环打印每循环的索引和元素值
{% endfor %}
# 补充:forloop
parentloop
counter0 # 循环的索引,从0开始
counter # 循环的索引,从1开始
revcounter # 倒序索引
revcounter0
first # 是否是第一次循环,True/False
last # 是否是最后一次循环,True/False
if判断
# if判断
{% if b %}
<p>baby</p>
{% elif s%}
<p>都来把</p>
{% else %}
<p>老baby</p>
{% endif %}
for循环和if判断混合使用
注意:empty
表示,for循环的可迭代对象内部没有元素时,执行的分支。
{% for foo in lll %}
{% if forloop.first %}
<p>这是我的第一次</p>
{% elif forloop.last %}
<p>这是最后一次啊</p>
{% else %}
<p>{{ foo }}</p>
{% endif %}
{% empty %}
<p>for循环的可迭代对象内部没有元素 根本没法循环</p>
{% endfor %}
with
起别名
在with
语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
另一个好处就是:可以起到缓存优化数据库的作用
# with起别名
{% with d.hobby.3.info as nb %}
<p>{{ nb }}</p> # 在with语法内可以直接使用简洁的nb,代替复杂的d.hobby.3.info
{% endwith %}
字典处理方法
keys
、values
、items
{% for foo in d.keys %}
<p>{{ foo }}</p>
{% endfor %}
{% for foo in d.values %}
<p>{{ foo }}</p>
{% endfor %}
{% for foo in d.items %}
<p>{{ foo }}</p>
{% endfor %}
自定义过滤器&标签&inclusion_tag
创建并使用自定义过滤器(filter)、标签(simple_tag)、inclusion_tag的流程完全一致。
相同的准备工作:
- 在应用下创建一个名字为
templatetags
的文件夹 - 在该文件夹内创建任意名字的py文件(如,
mytag.py
) - 在该
mytag.py
文件里面必须首先做如下配置:
from django import template
register = template.Library()
自定义和使用过滤器
功能:和内置过滤器一样,接收并处理视图层传过来的数据
注意:自定义过滤器和内置过滤器一样,最多只能接收两个参数;
# 定义,mytag.py
@register.filter(name='baby') # 给过滤器起一个名字 'baby'
def my_sum(v1, v2): # 该过滤器接受两个参数,并返回参数的和
return v1 + v2
#使用,xxx.html
{% load mytag %} # 类似先导入 模块名字 即mytag.py文件
<p>{{ n|baby:666 }}</p> # 使用该文件内的baby过滤器,两个参数分类在管道符前后
自定义标签simple_tag
功能:和过滤器类似,接收视图层传过来的数据并做进一步处理
注意:自定义的标签可以接收多个参数
# 定义,mytag.py
@register.simple_tag(name='plus')
def index(a,b,c,d): # 可以接收多个参数
return '%s-%s-%s-%s'%(a,b,c,d)
#使用,xxx.html
<p>{% plus 'jason' 123 123 123 %}</p> # 多个参数用空格隔开
自定义inclusion_tag
功能:将数据和html页面绑在一起,传给模版文件。数据一般是视图层从数据库里面取出的;html页面一般是模版文件的局部页面。
具体实现:
- 先定义一个方法;
- 该方法会将返回值交给这个局部的html页面,形成一个绑定了数据的html页面;
- 然后将这个绑定了数据的html页面传递给模版文件。
# 定义,mytag.py
@register.inclusion_tag('left_menu.html') # 局部left_menu.html页面接收left方法的返回值
def left(n):
data = ['第{}项'.format(i) for i in range(n)]
# 第一种
# return {'data':data} # 将data传递给left_menu.html
# 第二种
return locals() # 将data传递给left_menu.html
# 使用, xxx.html
{% left 5 %}
# 补充,也可以给这个inclusion_tag通过参数name起别名,否则直接使用函数名
局部left_menu.html
页面,仅仅是书写局部的html语句,在这里面接收left
方法的返回值,形成了一个绑定数据的html页面。
模版文件中使用标签left
的位置处,渲染这个绑定了数据的left_menu.html
页面。
<ul>
{% for foo in data %}
<li>{{ foo }}</li>
{% endfor %}
</ul>
模版继承
目的:较少模版文件的重复书写。相同的部分继承使用,不同的部分自定制。让页面的维护更加简单。
具体实现:
- 提前规划好父模版中子模版需要自定制的区域,该操作不影响父模版文件的内容。
{% block content %} # 设计子定制化区域,起名为'content'
模版内容
{% endblock %}
- 在子模版中,继承父模版,此时会子模版会完全继承父模版,两者的页面内容完全一样。
{% extends 'home.html' %}
- 定制子模版内容,在选定的区域内,定制自己的内容,不影响父模版的。
{% block content %} # 自定制名字为'content'的区域
子页面内容
{% endblock %}
总结&补充:
- 模版继承。类似对象的属性查找顺序,先使用自己的的,自己没有使用父类的。
- 一般情况下模版页面上应该至少有三块可以被修改的区域:
css\html\js
- 每一个子页面都有自己独立的css\html\js代码
- 一般情况下,模版的页面上划定的区域越多,那么该模版的扩展性就越高;但是如果太多,则因为模版结构混乱而造成可读性差,得不偿失。
{% block css %}
css文件
{% endblock %}
{% block content %}
html内容区域
{% endblock %}
{% block js %}
js内容区域
{% endblock %}
# 补充:使用父页面的部分内容的接触上再新增其他内容,使用super
{% block content %}
{{ block.super }}
# 再自定制化新的内容
{% endblock %}
模版导入
功能:将页面的某一个局部当成模块的形式,哪个地方需要就可以直接导入使用即可。
{% include 'side_bar.html' %}
# 模版导入时传递参数使用 include with