一、模板概念
DTL语言 - Django Template Language 你可能已经注意到我们在例子视图中返回文本的方式有点特别。 也就是说,HTML被直接硬编码在 Python代码之中。def current_datetime(request): now = datetime.datetime.now() html = "It is now %s." % now return HttpResponse(html)
尽管这种技术便于解释视图是如何工作的,但直接将HTML硬编码到你的视图里却并不是一个好主意。因此,将页面的设计和Python的代码分离开会更干净简洁更容易维护。 我们可以使用 Django的 模板系统 (Template System)来实现这种模式,这就是本章要具体讨论的问题
- 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。 站点设计的修改往往比底层 Python 代码的修改要频繁得多,因此如果可以在不进行 Python 代码修改的情况下变更设计,那将会方便得多。
- Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同部门)来完成。 设计者和HTML/CSS的编码人员不应该被要求去编辑Python的代码来完成他们的工作。
- 程序员编写 Python代码和设计人员制作模板两项工作同时进行的效率是最高的,远胜于让一个人等待另一个人完成对某个既包含 Python又包含 HTML 的文件的编辑工作。
python的模板:HTML代码+模板语法
# 视图函数 传输数据给模板 def inde_action(request): # 推荐写法 name = 'name1' list00 = [1,2,3,'hello','django'] dic = {'name':'name2','age':18} def test(): print('hello world') return 'fun-test' class Person(): pass # locals()方法可以返回视图函数内所有定义的 变量、函数、类等 return render(request, 'index.html', locals())
二、 模板语法 - 变量 : {{ 变量 }}
1、直接调用输出 - 相当于print
{#模板语言注释:前端看不到#} {#相当于print了该变量#}
模板语言之变量
字符串:{{ name }}
数字:{{ age }}
列表:{{ ll }}
元组:{{ tu }}
字典:{{ dic }}
{#只写函数名:相当于函数名(),执行该函数,显示的是返回值#}函数:{{ test }}
{#对象调用显示内存地址#}对象:{{ lqz }}
{# person_list=[p1,p2] #}列表套对象:{{ person_list }}
{# person_dic={'p1':p1} #}字典套对象:{{ person_dic }}
2、深度取值 - 获取对象内部值
深度查询
{# 一层 #}列表第0个值:{{ ll.0 }}
列表第4个值:{{ ll.3 }}
字典取值:{{ dic.name }}
字典取列表值:{{ dic.ll }}
{# 二层 #}对象取数据属性:{{ p1.name }}
对象取绑定给对象的函数属性:{{ p1.get_name }}
对象取绑定给类的函数属性:{{ p1.cls_test }}
对象取静态方法:{{ p1.static_test }}
把对象列表中,其中对象的一个年龄属性取出来:{{ person_list.1.age }}
{# 注意:不能调有参数的方法 #}字符串的方法:{{ name.upper }}
三、模板语法 - 过滤器 :{{ 位置参数1 | 过滤器函数 : 位置参数2}}
1- default :如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。
{{ value|default:"nothing" }}
2- length : 返回值的长度。它对字符串和列表都起作用
{{ value|length }} {#如果 value 是 ['a', 'b', 'c', 'd'],那么输出是 4。#}
3-
filesizeformat :
将值格式化为一个可读性高的文件尺寸{{ value|filesizeformat }} {# 如果 value 是 123456789,输出将会是 117.7 MB #}
4- date :格式化日期
value=datetime.datetime.now() {{ value|date:"Y-m-d" }} {# 不使用date:Nov. 9, 2018, 6:51 p.m. #} {# date:2018-11-09 #}
5- slice:切片操作
{#前闭后开区间#}
过滤器之slice:{{ ll|slice:'2:-1' }}
{#支持步长#}过滤器之slice-字符串:{{ name|slice:'0:3:3' }}
6- truncatechars :如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
{# 字符串 | truncatechars:显示的词数(三个起步)#}
过滤器之truncatechars:{{ 'dafddfafgadfgaasdgadgfadaf'|truncatechars:5 }}
{# da... #}过滤器之truncatewords:{{ '我 dfaf ga dfgaas 你 dgf adaf'|truncatewords:5 }}
{# 我 dfaf ga dfgaas 你 ... #}7- safe :是否转义输入框内的html、js元素等(使用-转义;不使用-不转义)
Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。 但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。 为了在Django中关闭HTML的自动转义,通过过滤器“|safe”的方式告诉Django这段代码是安全。{# h1='
你好
' #}过滤器之不用safe:{{ h1 }}
过滤器之用safe:{{ h1|safe }}
{# script='' #}过滤器之不用safe:{{ script }}
过滤器之用safe:{{ script|safe }}
![]()
8- 其他过滤器
过滤器 描述 示例 upper 以大写方式输出 {{ user.name | upper }} add 给value加上一个数值 {{ user.age | add:”5” }} addslashes 单引号加上转义号 capfirst 第一个字母大写 {{ ‘good’| capfirst }} 返回”Good” center 输出指定长度的字符串,把变量居中 {{ “abcd”| center:”50” }} cut 删除指定字符串 {{ “You are not a Englishman” | cut:”not” }} date 格式化日期 default 如果值不存在,则使用默认值代替 {{ value | default:”(N/A)” }} default_if_none 如果值为None, 则使用默认值代替 dictsort 按某字段排序,变量必须是一个dictionary {% for moment in moments | dictsort:”id” %} dictsortreversed 按某字段倒序排序,变量必须是dictionary divisibleby 判断是否可以被数字整除{{ 224 | divisibleby:2 }} 返回 True
escape 按HTML转义,比如将”<”转换为”<” filesizeformat 增加数字的可读性,转换结果为13KB,89MB,3Bytes等{{ 1024 | filesizeformat }} 返回 1.0KB
first 返回列表的第1个元素,变量必须是一个列表 floatformat 转换为指定精度的小数,默认保留1位小数 {{ 3.1415926 | floatformat:3 }} 返回 3.142 四舍五入 get_digit 从个位数开始截取指定位置的数字 {{ 123456 | get_digit:’1’}} join 用指定分隔符连接列表 {{ [‘abc’,’45’] | join:’’ }} 返回 abc45 length 返回列表中元素的个数或字符串长度 length_is 检查列表,字符串长度是否符合指定的值 {{ ‘hello’| length_is:’3’ }} linebreaks 用或
标签包裹变量 {{ “Hi David”|linebreaks }} 返回Hi
David
linebreaksbr 用
标签代替换行符 linenumbers 为变量中的每一行加上行号 ljust 输出指定长度的字符串,变量左对齐 {{‘ab’|ljust:5}}返回 ‘ab ’ lower 字符串变小写 make_list 将字符串转换为列表 pluralize 根据数字确定是否输出英文复数符号 random 返回列表的随机一项 removetags 删除字符串中指定的HTML标记 {{value | removetags: “h1 h2”}} rjust 输出指定长度的字符串,变量右对齐 slice 切片操作, 返回列表 {{[3,9,1] | slice:’:2’}} 返回 [3,9]{{ 'asdikfjhihgie' | slice:':5' }} 返回 ‘asdik’
slugify 在字符串中留下减号和下划线,其它符号删除,空格用减号替换{{ '5-2=3and5 2=3' | slugify }} 返回 5-23and5-23
stringformat 字符串格式化,语法同python time 返回日期的时间部分 timesince 以“到现在为止过了多长时间”显示时间变量 结果可能为 45days, 3 hours timeuntil 以“从现在开始到时间变量”还有多长时间显示时间变量 title 每个单词首字母大写 truncatewords 将字符串转换为省略表达方式{{ 'This is a pen' | truncatewords:2 }}返回``This is ...
truncatewords_html 同上,但保留其中的HTML标签{{ '
urlencode 将字符串中的特殊字符转换为url兼容表达方式 {{ ‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}} urlize 将变量字符串中的url由纯文本变为链接 wordcount 返回变量字符串中的单词数 yesno 将布尔变量转换为字符串yes, no 或maybeThis is a pen
' | truncatewords:2 }}返回``This is ...
{{ True | yesno }}{{ False | yesno }}{{ None | yesno }} ``返回 ``yes``no ``maybe
四、模板语法 - 标签 : {% tag %} …… {% endtag%}
标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 (例如{% tag %} ...
标签 内容 ... {% endtag %})。1- for标签:循环结构
列表的循环: {% for person in person_list %}
{{ person.name }}
{% endfor %} 字典的循环: {% for key in dic %}{{ key }}
{% endfor %} {% for val in dic.values %}{{ val }}
{% endfor %} {% for key,val in dic.items %}{{ key }}:{{ val }}
{% endfor %} 模板: {% for i in list %} {{ i }} {% endfor %}1-1 查看循环信息:{{ forloop }}
{% for foo in ll %} {{ forloop }}
{{ forloop.first }}--->{{ forloop.counter0 }}--->{{ forloop.revcounter }}----->{{ foo }}
{% endfor %} {% for foo in ll %} {% for i in person_list %} 取出外层是第几次循环 {{ forloop.parentloop.counter }}{{ forloop.first }}--->{{ forloop.counter0 }}--->{{ forloop.revcounter }}----->{{ foo }}
{% endfor %} {% endfor %}{{ forloop }}的输出信息: {'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 4, 'revcounter0': 3, 'first': True, 'last': False}
forloop.counter 当前循环的索引值(从1开始) forloop.counter0 当前循环的索引值(从0开始) forloop.revcounter 当前循环的倒序索引值(从1开始) forloop.revcounter0 当前循环的倒序索引值(从0开始) forloop.first 当前循环是不是第一次循环(布尔值) forloop.last 当前循环是不是最后一次循环(布尔值) forloop.parentloop 本层循环的外层循环
1-2 for …… empty :若循环对象为空执行empty内代码块
{% for person in person_list %}
{{ person.name }}
{% empty %}sorry,no person here
{% endfor %}2、if标签:逻辑判断
{% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。 {% if num > 100 or num < 0 %}
无效
{% elif num > 80 and num < 100 %}优秀
{% else %}凑活吧
{% endif %} 模板(if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断): {% if …… %} …… {% elif …… %} …… {% else %} …… {% endif %}3、with 标签: 取别名,简化变量名
{% with total=business.employees.count %} {{ total }} employee{{ total|pluralize }} {% endwith %} 模板: {% with 别名=原名 %} {{ 别名 }} …… {% endwith %}
4、csrf_token 标签:跨站请求伪造保护 {% csrf_token%}
五、自定义模板语法
1、自定义标签(
参数不限,但不能放在
if
for
语句中
)- @register.simple_tag
- 确认app在setting内的INSTALLED_APPS注册
- app下创建一个templatetags(固定名称)的文件夹(模块)
- 创建任意 .py 文件,如:my_tags.py
# 第一步,导入template from django import template #或者 from django.template import Library from django.utils.safestring import mark_safe register = template.Library() #register的名字是固定的,不可改变 @register.simple_tag(name = 'xxx') 装饰器内name可以对方法起别名 def simple_tag_multi(v1,v2): return v1 * v2 #一定要有返回值 @register.simple_tag def my_input(id,arg): result = "" %(id,arg,) return mark_safe(result)
- 在模板里:(新定定义的标签,过滤器,都要重启程序)
{# 加载自己的标签文件名 #} {% load mytag %} {# 使用标签 #} {% add_nb 'name'%} {% add_3 'name1' 'name2'%} 多个参数以空格区分
1-1 @register.inclusion_tag --- 返回可迭代对象(qureyset对象)
注意:普通的自定义标签返回的都只是一个值,而inclusion_tag返回一个可迭代对象# 第一步,导入template from django import template #或者 from django.template import Library register = template.Library() #register的名字是固定的,不可改变 # @register.inclusion_tag('模板路径',name=‘重命名’) @register.inclusion_tag('test.html',name = 'xxx') 装饰器内name可以对方法起别名 def my_inclusion_1(): # 逻辑代码块…… ret = Book.object.all() return {'books':ret} # 一定要有返回值,并且返回值必须是字典 @register.inclusion_tag('test.html') def my_inclusion_2(v1,v2): # 逻辑代码块…… ret = Book.object.all().filter(v1=v1,v2=v2) return {'books':ret}
{# 模板中使用自定义inclusion_tag #} {# 加载自己的标签文件名 #} {% load mytag %} {# 使用标签 #} {% my_inclusion_1 %} {% my_inclusion_2 'v1' 'v2'%} 多个参数以空格区分
2、自定义过滤器 - @register.filter
- 确认app在setting内的INSTALLED_APPS注册
- app下创建一个templatetags(固定名称)的文件夹(模块)
- 创建任意 .py 文件,如:my_filter.py
# 第一步,导入template from django.template import Library # 第二步,定义一个叫register的变量=template.Library() register = Library() # 第三步 # 装饰器内name可以对方法起别名 @register.filter(name='yyy') def str_add(str1, str2): # 业务逻辑…… return str1 + str2 # 一定要有返回值
- 在模板里:(新定定义的标签,过滤器,都要重启程序)
导入自己创建的过滤器文件 {% load myfilter %} {{'name'|str_add:'hello'}}