模板层
06 模板层
一. 模版语法
{{}}: 变量相关 {%%}: 逻辑相关
1. 注释是代码的规范
{# ... #}
2. 基本数据类型传值
int1 = 123
float1 = 11.11
str1 = '我也想奔现'
bool1 = True
list1 = ['小红', '姗姗', '花花', '茹茹']
tuple1 = (111, 222, 333, 444)
dict1 = {'username': 'jason', 'age': 18, 'info': '这个人有点意思'}
set1 = {'晶晶', '洋洋', '嘤嘤'}
# 基本数据类型都支持
{{ int1 }}
{{ float1 }}
{{ str1 }}
{{ bool1 }}
{{ list1 }}
{{ tuple1 }}
{{ dict1 }}
{{ set1 }}
3. 函数和类传值
def func():
print('我被执行了')
return '你的另一半在等你'
class MyClass(object):
def get_self(self):
return 'self'
@staticmethod
def get_func():
return 'func'
@classmethod
def get_class(cls):
return 'cls'
# 对象被展示到html页面上 就类似于执行了打印操作也会触发__str__方法
def __str__(self):
return 'cls'
obj = MyClass()
# 传递函数名会自动加括号调用 但是模版语法不支持给函数传额外的参数
{{ func }}
# 传类名的时候也会自动加括号调用(实例化)
{{ MyClass }}
# 内部能够自动判断出当前的变量名是否可以加括号调用 如果可以就会自动执行 针对的是函数名和类名
{{ obj }}
{{ obj.get_self }}
{{ obj.get_func }}
{{ obj.get_class }}
# 总结
'''
1. 如果计算结果的值是可调用的,它将被无参数的调用。 调用的结果将成为模版的值。
2. 如果使用的变量不存在, 它被默认设置为'' (空字符串) 。
'''
4. 模版语法的取值
django模版语法的取值 是固定的格式 只能采用“句点符”.
{{ dict1.username }}
{{ list1.0 }}</p>
{{ dict1.hobby3.info }}
5. 模板语法的优先级
点.
在模板语言中有特殊的含义。当模版系统遇到点.
,它将以这样的顺序查询:
'''
1. 字典查询(Dictionary lookup)
2. 属性或方法查询(Attribute or method lookup)
3. 数字索引查询(Numeric index lookup)
'''
二. Filters过滤器(注意: 过滤器只能最多有两个参数)
过滤器就类似于是模版语法内置的 内置方法.
django内置有60多个过滤器我们这里了解一部分即可
过滤器语法: {{数据|过滤器:可选参数}}
注意事项:
1. 过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
2. 过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。
3. 过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:', ' }}
4. '|'左右没有空格没有空格没有空格
Django的模板语言中提供了大约六十个内置过滤器我们这里介绍14种:
# 统计长度: 作用于字符串和列表。
{{ str1|length }}
# 默认值: 第一个参数布尔值是True就展示第一个参数的值否则就展示冒号后面的值
{{ bool1|default:'谁的布尔值为True谁就展示' }}
# 文件大小:
{{ file_size|filesizeformat }} # 9.8 KB
# 日期格式化: 将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等
{{ current_time|date }} # May 29, 2020
{{ current_time|date:'Y-m-d' }} # 2020-05-29
{{ current_time|date:'Y-m-d H:i:s' }} # 2020-05-29 01:31:09
# 切片操作: 支持步长
{{ list1|slice:'0:4:2' }}
# 切取字符: 如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾 (注意: 包含这三个点)
{{ info|truncatechars:9 }}
# 切取单词: 不包含三个点 按照空格切取, 不是识别单词语法
{{ msg|truncatewords:3 }}
# 移除特定的字符:
{{ msg|cut:' '}}
# 拼接操作:
# join
{{ info|join:'$' }}
# 加法: 数字就相加 字符就拼接
{{ int1|add:float1 }}
{{ str1|add:str1 }}
# 转义!!!!:
# 后端的转义
from django.utils.safestring import mark_safe
html_safe = mark_safe('<h1>哈哈哈</h1>')
{{ html }} # 普通的标签使用模板, 任然是模板
{{ html_safe }} # 后端的转义传值
{{ html|safe }} # 前端的转义
date参数介绍:
格式化字符 | 描述 | 示例输出 |
---|---|---|
a | 'a.m.' 或'p.m.' (请注意,这与PHP的输出略有不同,因为这包括符合Associated Press风格的期间) |
'a.m.' |
A | 'AM' 或'PM' 。 |
'AM' |
b | 月,文字,3个字母,小写。 | 'jan' |
B | 未实现。 | |
c | ISO 8601格式。 (注意:与其他格式化程序不同,例如“Z”,“O”或“r”,如果值为naive datetime,则“c”格式化程序不会添加时区偏移量(请参阅datetime.tzinfo ) 。 |
2008-01-02T10:30:00.000123+02:00 或2008-01-02T10:30:00.000123 如果datetime是天真的 |
d | 月的日子,带前导零的2位数字。 | '01' 到'31' |
D | 一周中的文字,3个字母。 | “星期五” |
e | 时区名称 可能是任何格式,或者可能返回一个空字符串,具体取决于datetime。 | '' 、'GMT' 、'-500' 、'US/Eastern' 等 |
E | 月份,特定地区的替代表示通常用于长日期表示。 | 'listopada' (对于波兰语区域,而不是'Listopad' ) |
f | 时间,在12小时的小时和分钟内,如果它们为零,则分钟停留。 专有扩展。 | '1' ,'1:30' |
F | 月,文,长。 | '一月' |
g | 小时,12小时格式,无前导零。 | '1' 到'12' |
G | 小时,24小时格式,无前导零。 | '0' 到'23' |
h | 小时,12小时格式。 | '01' 到'12' |
H | 小时,24小时格式。 | '00' 到'23' |
i | 分钟。 | '00' 到'59' |
I | 夏令时间,无论是否生效。 | '1' 或'0' |
j | 没有前导零的月份的日子。 | '1' 到'31' |
l | 星期几,文字长。 | '星期五' |
L | 布尔值是否是一个闰年。 | True 或False |
m | 月,2位数字带前导零。 | '01' 到'12' |
M | 月,文字,3个字母。 | “扬” |
n | 月无前导零。 | '1' 到'12' |
N | 美联社风格的月份缩写。 专有扩展。 | 'Jan.' ,'Feb.' ,'March' ,'May' |
o | ISO-8601周编号,对应于使用闰年的ISO-8601周数(W)。 对于更常见的年份格式,请参见Y。 | '1999年' |
O | 与格林威治时间的差异在几小时内。 | '+0200' |
P | 时间为12小时,分钟和'a.m。'/'p.m。',如果为零,分钟停留,特殊情况下的字符串“午夜”和“中午”。 专有扩展。 | '1 am' ,'1:30 pm' / t3>,'midnight','noon','12:30 pm' / T10> |
r | RFC 5322格式化日期。 | 'Thu, 21 Dec 2000 16:01:07 +0200' |
s | 秒,带前导零的2位数字。 | '00' 到'59' |
S | 一个月的英文序数后缀,2个字符。 | 'st' ,'nd' ,'rd' 或'th' |
t | 给定月份的天数。 | 28 to 31 |
T | 本机的时区。 | 'EST' ,'MDT' |
u | 微秒。 | 000000 to 999999 |
U | 自Unix Epoch以来的二分之一(1970年1月1日00:00:00 UTC)。 | |
w | 星期几,数字无前导零。 | '0' (星期日)至'6' (星期六) |
W | ISO-8601周数,周数从星期一开始。 | 1 ,53 |
y | 年份,2位数字。 | '99' |
Y | 年,4位数。 | '1999年' |
z | 一年中的日子 | 0 到365 |
Z | 时区偏移量,单位为秒。 UTC以西时区的偏移量总是为负数,对于UTC以东时,它们总是为正。 | -43200 到43200 |
三. 标签
1. for循环
forloop.first | 第一次循环返回True, 其余返回False |
---|---|
forloop.last | 最后一次循环返回False, 其余返回True |
forloop.counter | 当前循环次数. 从1开始 |
forloop.counter0 | 当前循环索引. 从0开始 |
forloop.revcounter | 当前循环次数取反 |
forloop.revcounter0 | 当前循环索引取反 |
forloop.parentloop | 本层循环的外层循环 |
展示格式:
{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 4, 'revcounter0': 3, 'first': True, 'last': False}
{'parentloop': {}, 'counter0': 1, 'counter': 2, 'revcounter': 3, 'revcounter0': 2, 'first': False, 'last': False}
{'parentloop': {}, 'counter0': 2, 'counter': 3, 'revcounter': 2, 'revcounter0': 1, 'first': False, 'last': False}
{'parentloop': {}, 'counter0': 3, 'counter': 4, 'revcounter': 1, 'revcounter0': 0, 'first': False, 'last': True}
{% for foo in list1 %}
<p>{{ forloop }}</p>
<p>{{ foo }}</p> # 一个个元素
{% endfor %}
2. if判断
# if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断
{% if bool1 %}
<p>1111</p>
{% elif int1 %}
<p>2222</p>
{% else %}
<p>3333</p>
{% endif %}
3. for与if混合使用
Copy{% for foo in list1 %}
{% if forloop.first %}
<p>这是我的第一次</p>
{% elif forloop.last %}
<p>这是最后一次啊</p>
{% else %}
<p>上面都不是才轮到我</p>
{% endif %}
{% empty %}
<p>for循环的可迭代对象内部没有元素 根本没法循环</p>
{% endfor %}
4. 处理字典values,keys,items方法
{% for foo in dict1.values %}
<p>{{foo}}</p>
{% endfor %}
{% for foo in dict1.keys %}
<p>{{foo}}</p>
{% endfor %}
{% for foo in dict1.items %}
<p>{{foo}}</p>
{% endfor %}
5. with起别名
在with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
dict1 = {'username': 'egon', 'hobby': ['吃', '喝', '玩', {'info': '他喜欢吃生蚝!!!'}]}
# 书写方式一: as语句
{% with dict1.hobby.3.info as nb %}
<p>{{ nb }}</p>
{# 与上面等同, 但是长语句, 还是使用with赋值来进行 #}
<p>{{ dict1.hobby.3.info }}</p>
{% endwith %}
# 书写方式二: 赋值
{% with nb=dict1.hobby.3.info %}
<p>{{ nb }}</p>
{# 与上面等同, 但是长语句, 还是使用with赋值来进行 #}
<p>{{ dict1.hobby.3.info }}</p>
{% endwith %}
四. 自定义过滤器、标签、inclusion_tag
1. 准备步骤
1. 在应用下创建一个名字”必须“叫templatetags文件夹
2. 在该文件夹内创建“任意”名称的py文件
3. 在该py文件内"必须"先书写下面两句话(单词一个都不能错)
from django import template
register = template.Library()
2. 自定义过滤器
强调: 自定义过滤器函数, 最大只能设有2个形参
from .templatetags.mytag import register
@register.filter(name='my_sum')
def abc(v1, v2): # abc函数名任意. 导入自定义过滤器使用的是上面指定的name的值
return v1 + v2
# 使用: (注意: 先导入我们自定义filter那个文件mytag)
{% load mytag %}
<p>{{ int1|my_sum:100 }}</p>
3. 自定义标签
# 自定义标签: 数可以有多个 类似于自定义函数
from .templatetags.mytag import register
@register.simple_tag(name='my_join')
def abc(a, b, c, d): # abc函数名任意. 导入自定义标签使用的是上面指定的name的值
return f'{a}-{b}-{c}-{d}'
# 使用: 标签多个参数彼此之间空格隔开(注意: 先导入我们自定义filter那个文件mytag)
{% load mytag %}
p>{% my_join 'json' 123 123 123 %}</p>
4. 自定义inclusion_tag
'''
内部原理:
先定义一个方法
在页面上调用该方法 并且可以传值
该方法会生成一些数据然后传递给一个html页面
之后将渲染好的结果放到调用的位置
'''
from .templatetags.mytag import register
@register.inclusion_tag('left_memu.html') # 注意: 这里传的是渲染的HTML文件, 不需要指定关键字name
def left(n):
data = ['第{}项'.format(i) for i in range(n)]
# 第一种: 将data传递给left_menu.html
# return {'data':data}
# 第二种: 将data传递给left_menu.html
return locals()
# left_memu.html
{% for foo in data %}
{% if forloop.first %}
<p>{{foo}}</p>
{% elif forloop.last %}
<p>{{ foo }}</p>
{% endif %}
{% endfor %}
# index使用(注意: 先导入我们自定义filter那个文件mytag)
{% load mytag %}
{% left 5 %}
五. 模板的继承
# 模版的继承 你自己先选好一个你要想继承的模版页面
{% extends 'home.html' %}
# 继承了之后子页面跟模版页面长的是一模一样的 你需要在模版页面上提前划定可以被修改的区域
{% block content %}
模版内容
{% endblock %}
# 子页面就可以声明想要修改哪块划定了的区域
{% block content %}
子页面内容
{% endblock %}
# 一般情况下模版页面上应该至少有三块可以被修改的区域, 这样每一个子页面就都可以有自己独有的css代码 html代码 js代码
{% block css %}
1.css区域
{% endblock %}
{% block content %}
2.html区域
{% endblock %}
{% block js %}
3.js区域
{% endblock %}
"""
一般情况下 模版的页面上划定的区域越多 那么该模版的扩展性就越高
但是如果太多 那还不如自己直接写
"""
六. 模版的导入
"""
将页面的某一个局部当成模块的形式
哪个地方需要就可以直接导入使用即可
"""
'''静态导入'''
{% include 'wasai.html' %}
'''动态导入'''
# 被导入的text.html
<p>{{ name }}</p> {# 这里的name就是"egon"#}
# 导入html的文件
{% include 'text.html' with name='"egon"' %}
# 不过上面的导入的参数是写死的. 如果你想动态的通过模板语法传参, 你可以这样
{% include 'text.html' with name=username %} {#注意哦! 这里的username是视图层传过来的哦!#}
# 被导入文件中如果想{{ name }}模板以后是字符串的格式你可以这也指定即可!
<p>'{{ name }}'</p> {#注意: 如果不加引号, 这种字符串的格式的话, 那么name模板传值以后就是一个变量.#}
七. 总结
# 模板语法的母亲 -> 注释
{# #}
# 模板语法2种书写语法
# 变量相关: {{}}
# 逻辑相关: {%%}
# 支持的数据类型:
# 基本数据类型: int float bool str tuple list set dict
# 函数和类: function, class
注意:
1. 默认调用拿到的是返回值.
2. 无法传值. 如果需要传值的类型, 那么这个模板语法就不会生效.
3. 类中定义__str__方法, {{obj}}会触发其执行.
# 模板语法的取值:
固定格式. 句点符. 支持连点, 支持索引, 支持键.
例子: {{ user.name.0.1.0.info }}
# 过滤器: 最多只能有2个参数
# 语法: {{ 数据|过滤器:可选参数 }}
# 过滤器介绍:
|length 获取长度
|default:默认值 指定默认值. 前面布尔值为False才展示后面指定的参数 内部使用return v1 or v2
|filesizeformat 返回人性化文件大小格式KB MB....
|date:'Y-m-d' 返回 年-月-日 时间格式
|slice:'0:4:2' 切片 支持步长
|truncatechars:9 截取字符 包含三点
|truncatewords:9 截取单词 不包含三点 以空格区分
|cut:' ' 移除特定字符
|join:'$' 拼接操作
|add:99 数字就加 字符就拼接
|safe 前端 取消转义
from django.util.safestring import mark_safe
res = mark_safe('<h1>我是你爸爸</h1>')
{{ res }} 后端 取消转义
# 标签
# for循环
{% for i in user_list %}
{{ forloop }}
forloop.first 循环到第一次 True
forloop.last 循环到最后一次 False
forloop.counter 当前循环次数
forloop.counter0 当前循环索引
forloop.revcounter 当前循环次数取反
forloop.revcounter0 当前循环索引取反
{% endfor %}
# if判断
{% if 条件 %}
...
{% elif %}
...
{% else %}
...
{% endif %}
# for与if混合使用
{% for i in user_list %}
{% if forloop.first %}
...
{% if forloop.last %}
...
{% endfor %}
{% empty %}
迭代对象为空时触发
{% endfor %}
# 处理字典的values, keys, items方法
# with取别名
{% with user.name.0.1.0.info as xxx %}
{% with xxx=user.name.0.1.0.info %}
{{ xxx }}
{% endwith %}
# 自定义过滤器
# 三步骤:
1. 先在需要使用过滤器的应用中创建templatetags文件夹
2. 接着进入文件夹中创建任意名称的.py文件. --> mytag.py
3. 写入以下固定格式的内容:
from django import template
register = template.Library()
# 自定义过滤器: 最多2个参数
# 视图层定义
from templatetags.mytag import register
@register.filter(name='过滤器名称 -> my_sum')
def 任意函数名(v1, v2):
return v1 + v2
# 模板层使用
{% load mytag %}
{{ v1|my_sum:v2 }}
# 自定义标签: 任意参数
# 视图层定义
from templatetags.mytag import register
@register.simple_tag(name='标签名称 -> my_join')
def 任意函数名(a, b, c, d):
return f'{a}-{b}-{c}-{d}'
# 模板层使用
{% load mytag %}
{{ my_join 111 222 333 444 }}
# 自定义inclusion_tag
# 视图层定义
from templatetags.mytag import register
@register.inclusion_tag('需要传递数据的html文件 -> index.py')
def left(n):
data = [f'第{i}项' for i in range(n)]
return locals() # 传递数据方式1
# return {"data": data} # 传递数据方式2
# index.py定义
<ul>
{% for item in data %}
<li>{{ item }}</li>
{% endfor %}
</ul>
# 模板层使用
{% load mytag %}
{% left 5 %}
# 模板的继承
# 子页面声明需要继承的模板页面
{% extends '模板页面名' %}
# 需要被划分模板页面中的某块区域
{% block context %}
...
{% endblock %}
# 子页面声明替换区域
{% block context %}
...
{% endblock %}
# 一般一情况下子页面有3种独立的形式. 提示: 太多不如不继承
js, css, html
# 模板的导入
{% include '.html' %}