第八章 Django的模板
MVC:model view(html) controller(控制器,路由传递指令,业务逻辑)
MTV:model(ORM操作) template(html) view(业务逻辑)
{{ }}表示变量,在模板渲染的时候替换成值,{% %}表示逻辑相关的操作。
8.1. 变量
通过key取值
传值时,本质是字符串的替换
.索引、.key、.属性、.方法
变量的 . 方法的优先级是:dict —> 属性、方法—>索引
{{ 变量名 }}变量名由字母数字和下划线组成。
点(.)在模板语言中有特殊的含义,用来获取对象的相应属性值。
变量 {{ }}
{% %} 表示逻辑相关的操作
对象调用__str__方法
.索引 .key .属性 .方法
{{hobby.0}} ---索引不能写负的,只支持正向的 ---列表可以用索引取
{{dic.name}}
{{dic.keys}}---字典用.key直接取
{{dic.values}}
当模板中遇到一个(.)时,会按照如下的顺序去查询:1在字典中key查询,2属性或方法 3数字索引8.1. 1 取值
1. 列表
hobby.索引,只支持正向索引
hobby = [‘movies‘, ‘musics‘, ‘reading‘, ‘play badminton‘]
{{hobby.5}}2. 字典
通过key取值
没有get方法。也可以使用request对象取值
模版里方法不用加括号
hobby = [‘movies‘, ‘musics‘, ‘reading‘, ‘play badminton‘]
dic = {1: a, 2: b, 3: hobby}
{{ dic.3.1 }}
<br>
{{ dic.keys }}
<br>
{{ dic.values }}
<br>
{{ dic.items }}
<br>
{{ request }}3. 类
定义的方法不能使用形参,否则无法使用
# views.py中
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def talk(self):
return ‘咱也不知道,咱也不敢问‘
def __str__(self):
return ‘<Person obj: {}-{}>‘.format(self.name, self.age)
def my_test(request):
person_obj = Person(‘henry‘, 19)
return render(request, {‘person_obj‘: person_obj}){{ person_obj }}
<br>
{#此时talk不能传参#}
{{ person_obj.talk }}8.1.2 filter(过滤器)
作用:修改变量的显示结果
语法:{{value|filter_name:参数}}
1. default
default用法,变量为False显示默认值
default和指定值之间不能有空格
<p>{{xxx}}</p>
<p>{{xxx|default:变量/指定值}}</p>
<p>{{xxx|default:‘‘}}</p># settings.py中的templates中的options中设置 # 只有变量不存在时有效 ‘string_if_invalid‘ = ‘变量不存在‘
2. filesizeformat
文件默认byte为单位
文件大小格式化
# 文件单位换算,最大有效单位为 PB
{变量|filesizeformat}3. add
数值加法
字符串/list拼接
# 结果为6,优先使用数字的加法,有其他类型时,进行拼接
{{2|add:‘4‘}hobby = [‘movies‘, ‘musics‘, ‘reading‘, ‘play badminton‘]
{{hobby|add:hobby}}
# add:hobby之间不能有任何空格,否则会报错4. lower / upper / title(所有单词首字母大写)
5. ljust / rjust / center
"{{‘Django‘|center:"15" }}"
Ifvalueis"Django",theoutputwillbe" Django ".6. length
计算长度
string = ‘hello bugs‘
li = [1,2]
{{string|length}}
{{li|length}}7. slice
string 和list
li = [1,2,3,4]
{{li|slice:‘1:3‘}} # [2, 3]
{{ li|slice:‘2‘ }} # [1, 2]
{{ li|slice:‘-1‘ }} # [1, 2, 3]
{{li|slice:‘-2::-1‘}} # [3, 2, 1]
{{ li |slice:‘::-1‘ }} # [4, 3, 2, 1]8. first /last
取当前第一个或最后一个
{{li|last}}
{{li|first}}9. join
{{li|join‘:‘}}10. truncatechars
其后必须有参数,少于3时均为...
string = ‘welcome to China, welcome to BeiJing‘
{{string|truncatechars:‘10‘}}
# 会有三个点,也要占位
welcome...
{{string|truncatewords:‘10‘}}
# 对中文无效,10个单词,10个单词+3个点11. date
{{ value|date:"Y-m-d H:i:s"}}
django模版中的日期格式化,和python中不同
import datetime
now = datetime.datetime.now()
{{now|date:‘Y-m-d H:i:s‘}}# settings.py DATETIME_FORMAT = ‘Y-m-d H:i:s‘ DATE_FORMAT = ‘Y-m-d‘ TIME_FORMAT = ‘H:i:s‘ USE_L10N = False
12. safe/urlize
Django的模板中会对HTML标签和JS等语法标签进行自动转义
安全,告诉Django不用做转义
把非字符串类型转换为字符串类型
js、超链接
# 作为render传参中字典的元素
‘value‘ : "<a href=‘#‘>点我</a>"
{{ value|safe }}13. divisibleby
{# 被2整除 #}
{{forloop.counter|divisibleby:2}}8.1.3 自定义filter
在app下创建一个名为templatetags的python包(包名是固定的)
创建xxx.py 文件,文件名自定义(my_tags)
导入模块、注册register、添加装饰器
# app/templatetags/xxx.py
from django import template
# register 名称不能改变
register = template.Library()
# 参数可以省略,形参最多有两个r
@register.filter
def add_(value, arg):
return ‘{}-{}‘.format(value, arg)
# 使用
{% load my_tags %}
{{‘henry‘|add_:‘hello‘}}- 使用filter指定的函数名
# 定义
@register.filter(name=‘henry‘)
def add_(value, arg):
return ‘{}-{}‘.format(value, arg)
# 使用
{% load my_tags %}
{{‘henry‘|henry:‘hello‘}}- 取消转义
value = ‘https://www.baidu.com‘
# 自定义,不会转义
@register.filter(is_safe=True)
def add_(value, arg):
return ‘{}{}‘.format(value, arg=None)
# 自定义,不会转义
from django.utils.safestring import mark_safe
@register.filter
def add_(value, arg):
return mark_safe(‘{}-{}‘.format(value, arg))- 示例
加法{{ a }} + {{ b }} =
{{ a|add:b }}
<br>
减法
{{ a }} - 1 =
{{ a|add:-1 }}
<br>
乘法
{{ a }} * {{ b }} =
{% widthratio a 1 b %}
<br>
除法
{{ a }} * {{ b }} =
{% widthratio a b 1 %}
{% load show_a %}
<br>8.2. 逻辑相关
8.2.1 for 循环
没有则为空字典
for循环可用的一些参数:
| Variable | Description |
|---|---|
| forloop.counter | 当前循环的索引值(从1开始) |
| forloop.counter0 | 当前循环的索引值(从0开始) |
| forloop.revcounter | 当前循环的倒序索引值(到1结束) |
| forloop.revcounter0 | 当前循环的倒序索引值(到0结束) |
| forloop.first | 当前循环是不是第一次循环(布尔值) |
| forloop.last | 当前循环是不是最后一次循环(布尔值) |
| forloop.parentloop | 本层循环的外层循环 |
1. 语法示例
{% empty %}
{# 整除,需要过滤器 #}
{% if forloop.counter|divisibleby:2 %}
{# 偶数行、偶数列 #}
{% if forloop.partent.forloop.counter|divisibleby:2 %}{# 如果没有循环,显示empty中的内容 #}
{% empty %}
<td colspan=‘5‘ style=‘text-algin:center‘>没有数据<\td>2. 示例
Template所需要的变量都由view中函数提供
{# hobby = [‘movie‘, ‘music‘, ‘reading‘]
dic = [hobby, hobby, hobby] #}
{% for i in dic %}
<tr>
{% for i in i %}
{% if forloop.counter|divisibleby:2 and forloop.parentloop.counter|divisibleby:2%}
<td style="color:red">
{{ i }}
</td>
{% else %}
<td>
{{ i }}
</td>
{% endfor %}
</tr>
{% empty %}
{# colspan=4 表示合并单元格 #}
<td colspan="4"style="text-align:center;">空空如也</td>
{% endfor %}8.2.2 if 判断
if语句支持 and、or、==、>、 < 、!=、 <=、 >=、 in、 not in、 is、 is not
逻辑运算(不支持连续判断)
成员运算
身份运算
不支持 + (算术运算和连续判断),如有需求使用过滤器
{% if 条件判断 %}
显示的内容
{% elif %}
显示的内容
{% else %}
显示的内容
{% endif %}- 连续判断对比
# python, 相当于,10 > 5 and 5 > 1, True 10 > 5 > 1 # js,相当于, 10 > 5 --> true, true(1) > 1,False 10 > 5 > 1 # 模版中,必须加上空格,10 > 5 --> true, true(1) > 1,False 10 > 5 > 1
8.2.3 with
别名,只在with标签内部生效
li = [1,2,3,4]
{% with li.2 as x %}
{{ x }}
{% endwith %}
{% with x=li.2 %} {{ x }}{% endwith %}
8.2.4 注释
不做任何渲染
即不替换任何元素
{# 任何效果都没有 #}
<!--html 注释,html渲染,页面不显示,元素中有-->8.2.5 csrf_token
跨站请求伪造,Cross-site request forgery
这个Token的值必须是随机的,不可预测的。
{# form表单中加入 #}
{# form表单中有一个隐藏标签 #}
{% csrf_token %}
name = csrfmiddlewaretokenNote(2)
Django的模版语言不支持连续判断
属性的优先级大于方法
8.2.6 母版和继承
母版:就是一个html页面,提取到多个页面的公共部分,并在页面中定义多个block
普通的html页面,公共的部分提取出来,并定义block、用子页面替换
{# 母版 #}
{% block content %}
子页面的内容
{% endblock %}- 使用
{% extends ‘base.html‘ %}
{% block content %}
子页面
{% endblock %}Note(4)
把{% extends ‘base.html‘ %}写在第一行
如果想展示标签内容,需要写在block中
base.html需要引号,否则视为变量,可以在render中传入此变量
可以单独为css样式或js定义block
8.2.7 组件
某一功能的html代码段
{# 某一块功能的拆解,只是某一段代码 #}
{% include ‘component.html‘ %}8.2.8 静态文件
通过static寻找静态文件
{% load static %} {# 或 #} {% load staticfiles %}
<link rel="stylesheet" href=‘{% static "css/dashboard.css" %}‘>- 通过获取静态文件名
{% load static %}
{% get_static_prefix %}
<link rel="stylesheet" href="{% get_static_prefix %}css/dashboard.css">- 给静态文件命别名
{% load static %}
{% get_static_prefix as file_path %}
<link rel="stylesheet" href="{{ file_path }}css/dashboard.css">8.2.9 simple_tag
自定义标签,对参数没有限制,较为灵活,类似自定义filter
定义注册simpletag(标签)
# 与自定义filter在同一文件中
from django import template
@register.simple_tag(name=‘xxx‘)
def join_str(*args, **kwargs):
return ‘{}--{}‘.format(‘*‘.join(args), ‘+‘.join(kwargs.values()))- 使用方法
{# 与自定义filter在同一文件下,这里使用 my_tags.py #}
{% load my_tags %}
{# 注意关键字传参的变量 #}
{% xxx ‘1‘ ‘2‘ k1=‘v1‘ k2=‘v2‘ %}和filter的区别
simpletag是标签,参数不受限制,使用{%%}
filter是过滤器,参数最多有两个。使用{{ }}
装饰器不同
返回值不同
8.2.10 inclusion_tag
最终返回html代码段
可以用于分页
返回值是必须是dict类型
# my_tag.py
@register.inclusion_tag(‘page.html‘)
def page(num):
return {‘num‘: range(1, num+1)}{# page.html #}
{# bootstarp,组件中的分页代码 #}
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% for i in num %}
<li><a href="#">{{ i }}</a></li>
{% endfor %}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>- 在展示页面使用
{# xxx.html #}
{% load my_tags %}
{% page 10 %}3. 自定义方法的使用流程
filter、simple_tag、inclusion_tag
1. 在已注册的App下建立templatetags的pyhton 包
2. 在包中,创建py文件
3. 在py文件中导入模块,并注册
from django import template register = template.Library()
4. 写函数
@register.inclusion_tag(‘page.html‘)
def page(num):
return {‘num‘: range(1, num+1)}5. 写模版
组件是固定、不灵活
{# page.html #}
{% for i in num %}
{{i}}
{% endfor %}6. 使用
在返回页面使用
{# filter #}
{% load my_tag %}
{{‘xxx‘|add_:‘a‘}}
{# simple_tag #}
{% load my_tag %}
{% join_str 1 2 k1=‘v1‘ k2=‘v2‘ %}
{# inclusion_tag #}
{% load my_tag %}
{% page 4 %}