Django基础之模板层
模板层Templates
Django提供了模板系统 (Template System)用来专门定制html文件,一个html文件称之为一个模板
-
对于静态页面来说,直接编写就好
-
而针对动态页面,django额外提供了专门的模板语言(Django template language,简称DTL),允许我们在页面中嵌入模板变量,这便为后期为页面动态填充内容提供了可能性。
DTL是模板系统的核心,因此django的模板系统也被等同于DTL
模板语法的使用
模板语法传值
方式一:字典
return render(request, 'demo02.html', {'n1': name, 'a1': age}) # 传值方式1:精准传值,不浪费资源,针对多资源的传递书写麻烦
方式二:locals()
return render(request,'demo02.html', locals()) # 传值方式2:将函数名称空间中所有的名字全部传递,名字过多并且不使用的情况下比较浪费资源
locals():当前函数中的所有局部变量,并且组装成字典的形式
变量
- {{}}:主要与数据值相关,跟变量相关
- {%%}:主要与逻辑相关
传值的特性:
1.基本数据类型正常展示
2.文件对象也可以展示并调用方法,模板语法会自动加括号
3.函数名会自动加括号执行并将返回值展示到页面上(不支持额外传参)
4.类名也会自动加括号调用,产生一个对象
5.对象则不会
"""
1.模板语法中取值使用点语法
2.针对需要加括号调用的名字,django模板语法会自动加括号调用,你直接写函数名就行
3.模板语法的注释前端浏览器是无法查看的,地下控制台查看不到 {##}
"""
基本使用:
views.py
# 模板语法
def template_func(request):
# python基本数据类型
f = 1.11
i = 666
s = 'hello world'
lst = [1, 2, 3, 4]
d = {'name': 'jason', 'age': 18}
t = (11, 22, 33, 44)
se = {666, 333, 999, 222}
b = True
# 函数
def func():
return 'func函数'
# 类
class Login():
def __init__(self, name):
self.name = name
def get_obj(self):
return '绑定给对象的方法'
@classmethod
def get_cls(cls):
return '绑定给类的方法'
@staticmethod
def get_static():
return '静态方法'
obj = Login('http') # 对象
return render(request, 'template.html', locals())
html:
<p>{{ f }}</p>
<p>{{ i }}</p>
<p>{{ s }}</p>
<p>{{ lst }}</p>
<p>{{ d }}</p>
<p>{{ t }}</p>
<p>{{ se }}</p>
<p>{{ b }}</p>
{# 函数 #}
<p>{{ func }}</p>
<p>{{ Login }}</p>{# 类名 #}
深度查询之句点符的使用
变量名中不能有空格或者标点符号,但是有一个例外,点(".")可以出现在变量中,点后的可以是字典相关(字典的key或者字典内置方法)、对象的属性或方法、数字索引,如下所示
<hr>
<h3>深度查询句点符</h3>
<p>{{ lst.0 }}</p> {# 列表.索引 #}
<p>{{ d.age }}</p> {# 字典.key #}
<p>{{ obj.name }}</p> {# 对象.属性 #}
<p>{{ obj.get_obj }}</p> {# 对象.方法 #}
<p>{{ obj.get_cls }}</p>
<p>{{ obj.get_static }}</p>
过滤器
过滤器类似于python的内置函数,用来把变量值加以修饰后再显示,具体语法如下
#1、
{{ 变量名|过滤器名 }}
#2、链式调用:上一个过滤器的结果继续被下一个过滤器处理
{{ 变量名|过滤器1|过滤器2 }}
#3、有的过滤器取需要参数
{{ 变量名|过滤器名:传给过滤器的参数 }}
常用内置过滤器
#0、default
#作用:如果一个变量值是False或者为空、None,使用default后指定的默认值,否则,使用变量本身的值,如果value=’‘则输出“nothing”
{{ value|default:"nothing" }}
#1、default_if_none
#作用:如果只针对value是None这一种情况来设置默认值,需要使用default_if_none
#只有在value=None的情况下,才会输出“None...”,
{{ value|default_if_none:"None..." }}
#2、length
#作用:返回值的长度。它对字符串、列表、字典等容器类型都起作用,如果value是 ['a', 'b', 'c', 'd'],那么输出是4
{{ value|length }}
#3、filesizeformat
#作用:将值的格式化为一个"人类可读的"文件尺寸(如13KB、4.1 MB、102bytes等等),如果 value 是 12312312321,输出将会是 11.5 GB
{{ value|filesizeformat }}
#4、date
#作用:将日期按照指定的格式输出,如果value=datetime.datetime.now(),按照格式Y-m-d则输出2019-02-02
{{ value|date:"Y-m-d" }}
#5、slice
#作用:对输出的字符串进行切片操作,顾头不顾尾,如果value=“egon“,则输出"eg"
{{ value|slice:"0:2" }}
#6、truncatechars
#作用:如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾,如果value=”hello world egon 嘎嘎“,则输出"hello...",注意8个字符也包含末尾的3个点
{{ value|truncatechars:8 }}
#7、truncatewords
#作用:同truncatechars,但truncatewords是按照单词截断,注意末尾的3个点不算作单词,如果value=”hello world egon 嘎嘎“,则输出"hello world ..."
{{ value|truncatewords:2 }}
后端也可以处理前端的标签
from django.utils.safestring import mark_safe
ss = mark_safe('<h1>hello</h1>')
# 后端处理前端的问题:是把前端的当成字符串来处理
示例:
views.py
def template_func(request):
# 过滤器
de = []
de1 = [4, ]
fa = False
file_data = 5952628
# 日期
from datetime import date, datetime
ctime1 = date.today()
ctime2 = datetime.today()
s1 = 'hello world lqz khn uvr cbjkgra'
h1 = '<h1>哈哈哈哈</h1>'
s1 = "<script>confirm(123)</script>"
# 后端也可以处理前端的标签
from django.utils.safestring import mark_safe
ss = mark_safe('<h1>hello</h1>')
# 后端处理前端的问题:是把前端的当成字符串来处理
return render(request, 'template.html', locals())
html
<h3>过滤器</h3>
{# 增加数字,拼接字符 #}
<p>{{ i|add:30 }}</p>
<p>{{ s|add:'hahaha' }}</p>
{#如果变量为空,设置默认值,空数据,None,变量不存在,都使用给定的默认值。否则,使用变量的值。#}
<p>{{ de|default:"空列表" }}</p>
<p>{{ de1|default:"空列表" }}</p>
<p>{{ fa|default:"假的" }}</p>
{# 计算长度,只有一个参数 #}
<p>{{ lst|length }}</p>
{# 计算文件大小 #}
{#单位换算展示,可以自己转换成最合适的单位#}
<p>{{ file_data|filesizeformat }}</p>
{# 日期 #}
<p>{{ ctime1|date:'Y-m-d' }}</p>
<p>{{ ctime2|date:'Y年-m月-d日 H时:i分:s秒' }}</p>
{# 字符串切片 #}
<p>{{ s1|slice:"2:-1" }}</p>
<p>{{ s1|slice:"2:5" }}</p>
{#截断字符,至少三个起步,因为会有三个省略号 #}
<p>{{ s1 |truncatechars:"6" }}</p>
{# hel... #}
{#截断文字,以空格做区分,这个不算省略号#}
<p>{{ s1 |truncatewords:"3" }}</p>
{# hello world lqz ... #}
<p>{{ h1 }}</p> {# 默认是不识别的 #}
<p>{{ s1 }}</p>
<p>{{ h1|safe }}</p>
<p>{{ s1|safe }}</p>
<p>{{ ss }}</p>
{# 大写和小写 #}
<p>{{ 'name'|upper }}</p>
<p>{{ 'LQZ'|lower }}</p>
其他过滤器(了解)
详见官网:https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#ref-templates-builtins-filters
过滤器 | 描述 | 示例 |
---|---|---|
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_if_none 如果值为None, 则使用默认值代替 |
dictsort | 按某字段排序,变量必须是一个dictionary | |
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\n\nDavid”|linebreaks }} 返回HiDavid |
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' |
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标签 | {{ 'This is a pen' | truncatewords:2 }}返回‘This is ...’ |
urlencode | 将字符串中的特殊字符转换为url兼容表达方式 | {{‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}} |
urlize | 将变量字符串中的url由纯文本变为链接 | |
wordcount | 返回变量字符串中的单词数 | |
yesno | 将布尔变量转换为字符串yes, no 或maybe | {{ True | yesno }}{{ False | yesno }}{{ None | yesno }} 返回 yesno maybe |
---- | ---- | ---- |
标签
模板中的标签的格式为
# 1、
{% 标签名 %}
# 2、大多数标签都需要接收参数
{% 标签名 参数1 参数2 %}
# 3、一些标签需要有开始{% tag %}和结束标记{% endtag %}
{% 标签名 %}
...内容...
{% end标签名 %}
for标签
1、遍历每一个元素:
{% for i in lst %}
<p>{{ i }}</p>
{% endfor %}
2、遍历一个字典:
{% for key in d %}
<p>{{ key }}</p>
{% endfor %}
3、字典的三剑客
{# 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>
{# 取元组内部的值 #}
{# <p>{{ foo.0 }}</p> #}
{% endfor %}
{% for key,val in d.items %}
<p>{{ key }}:{{ val }}</p>
{% endfor %}
结果为:
name
age
gender
jason
18
famale
('name', 'jason')
('age', 18)
('gender', 'famale')
name:jason
age:18
gender:famale
4、循环序号可以通过{{ forloop }}显示
forloop.counter The current iteration of the loop (1-indexed) 当前循环的索引值(从1开始)
forloop.counter0 The current iteration of the loop (0-indexed) 当前循环的索引值(从0开始)
forloop.revcounter The number of iterations from the end of the loop (1-indexed) 当前循环的倒序索引值(从1开始)
forloop.revcounter0 The number of iterations from the end of the loop (0-indexed) 当前循环的倒序索引值(从0开始)
forloop.first True if this is the first time through the loop 当前循环是不是第一次循环(布尔值)
forloop.last True if this is the last time through the loop 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环
具体使用:
{% for foo in lst %}
<p>{{ forloop }}</p>
{# 还可以用点语法取出内部的属性 #}
{#<p>{{ forloop.counter0 }}</p>#}
{% endfor %}
5、for … empty
循环的值是空,就执行empty里面的内容
lst = []
{% for foo in lst %}
<p>{{ foo.name }}</p>
{% empty %}
<p>列表为空</p>
{% endfor %}
if 标签
# {% if %}会对一个变量求值,如果它的值是True(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
{% if num > 100 or num < 0 %}
<p>无效</p>
{% elif num > 80 and num < 100 %}
<p>优秀</p>
{% else %}
<p>凑活吧</p>
{% endif %}
# if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
with起别名
d = {'username':'kevin','age':18,'info':'这个人有点意思','hobby':[111,222,333,{'info':'NB'}]}
{% with d.hobby.3.info as nb %}
<p>{{ nb }}</p>
在with语法内就可以通过as后面的别名快速的使用到前面非常复杂获取数据的方式
<p>{{ d.hobby.3.info }}</p>{# 与上面是等价的#}
{% endwith %}
csrf_token标签
之前提交方式是post就需要去settings中注释一行,现在可以在form表单中设置,就可以提交了。
<form action="" method="post">
{% csrf_token %}
<input type="submit">
结果:
前端Elements控制台中会直接变成:
<input type="hidden" name="csrfmiddlewaretoken" value="1sWyohvTZjU4xicEYLkbZRA01EbJxG3HNyBuBxfmezVD8PMv4EJIsd185cLQa5vA">
更多内置标签与过滤器:https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#ref-templates-builtins-tags
模板的导入和继承
在实际开发中,模板文件彼此之间可能会有大量冗余代码,为此django提供了专门的语法来解决这个问题,主要围绕三种标签的使用:include标签、extends标签、block标签,详解如下
模板的继承之extends标签、block标签
模板中:
{% block 标记的名字 %}
在模板中是把能够替换的内容直接放入block中,其他不要动
{% endblock %}
子模版:
{% extends 'home.html' %}
extends 标签是这里的关键。它告诉模版引擎,这个模版“继承”了另一个home.html模版中的所有元素。
{% block 标记的名字 %}{# 直接拿这模板中的名字来改就行 #}
子模版中替换的内容
{% endblock %}
Django模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承可以让您创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版替换的 block 。一个模板页面中也不要设置太多block。
被block标记的位置就是子模版可以替换的位置
# 一个模板页面中应该至少有3块内容可以被替换
1. css
2. js
3. html
具体使用:
模板html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
{% block css %}
{% endblock %}
</head>
<body>
<div class="panel panel-primary">
{% block aa %}
<div class="panel-heading">py25的兄弟们最nb</div>
{% endblock %}
<div class="panel-body">
{% block content %}
<div class="jumbotron">
<h1>洋哥带的学员最NB</h1>
<p>...</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
{% endblock %}
</div>
</div>
{% block js %}
{% endblock %}
</body>
</html>
子模板:
更改模板中标记为block content的位置。
{% extends 'home.html' %}
{% block css %}
<style>
h1 {
color: red;
}
</style>
{% endblock %}
{% block content %}
<form action="">
<h1>登录页面</h1>
<p>username: <input type="text" class="form-control"></p>
<p>password: <input type="text" class="form-control"></p>
<p>
<input type="submit" value="登录" class="btn btn-primary">
</p>
{% include 'welcome.html' %}
</form>
{% endblock %}
{% block js %}
<script>
</script>
{% endblock %}
模板的导入之include标签
作用:在一个模板文件中,引入/重用另外一个模板文件的内容,
示例:
先写一个页面welcome.html
<h1>欢迎你的光临</h1>
<h1>欢迎你的光临</h1>
home.html:
{% include 'welcome.html' %}
就代表把welcome.html中的所有内容都引入进来