第八章 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 取值
-
hobby.索引,只支持正向索引
hobby = ['movies', 'musics', 'reading', 'play badminton'] {{hobby.5}}
2. 字典
-
通过key取值
-
-
模版里方法不用加括号
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显示默认值
-
<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
-
数值加法
-
# 结果为6,优先使用数字的加法,有其他类型时,进行拼接 {{2|add:'4'}
hobby = ['movies', 'musics', 'reading', 'play badminton'] {{hobby|add:hobby}} # add:hobby之间不能有任何空格,否则会报错
4. lower / upper / title(所有单词首字母大写)
"{{'Django'|center:"15" }}" Ifvalueis"Django",theoutputwillbe" Django ".
6. length
string = 'hello bugs' li = [1,2] {{string|length}} {{li|length}}
7. slice
-
string 和
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}}
{{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模版中的日期格式化,
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不用做转义
-
把非字符串类型转换为字符串类型
-
# 作为render传参中字典的元素 'value' : "<a href='#'>点我</a>" {{ value|safe }}
{# 被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循环可用的一些参数:
Description | |
---|---|
forloop.counter | 当前循环的索引值(从1开始) |
forloop.counter0 | 当前循环的索引值(从0开始) |
forloop.revcounter | 当前循环的倒序索引值(到1结束) |
forloop.revcounter0 | 当前循环的倒序索引值(到0结束) |
forloop.first | 当前循环是不是第一次循环(布尔值) |
forloop.last | 当前循环是不是最后一次循环(布尔值) |
forloop.parentloop |
1. 语法示例
{# 整除,需要过滤器 #} {% if forloop.counter|divisibleby:2 %} {# 偶数行、偶数列 #} {% if forloop.partent.forloop.counter|divisibleby:2 %}
{# 如果没有循环,显示empty中的内容 #} {% empty %} <td colspan='5' style='text-algin:center'>没有数据<\td>
2. 示例
{# 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
-
别名,只在
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 = csrfmiddlewaretoken
Note(2)
-
Django的模版语言不支持连续判断
-
属性的优先级大于方法
8.2.6 母版和继承
-
母版:就是一个html页面,提取到多个页面的公共部分,并在页面中定义多个block
-
普通的html
{# 母版 #}
{% block content %}
子页面的内容
{% endblock %}
- 使用
{% extends 'base.html' %}
{% block content %}
子页面
{% endblock %}
Note(4)
-
把{% extends 'base.html' %}写在第一行
-
如果想展示标签内容,需要写在block中
-
base.html需要引号,否则视为变量,可以在render中传入此变量
-
可以单独为css样式或js定义block
8.2.7 组件
{# 某一块功能的拆解,只是某一段代码 #}
{% include 'component.html' %}
8.2.8 静态文件
{% 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
-
# 与自定义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文件
from django import template register = template.Library()
@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 %}