10-模板层
楔子
将前端页面和Python 的代码分离是一种的开发模式。 为此 Django专门提供了模板系统 (Template System,即模板层)来实现这种模式。
Django 的模板 = HTML代码 + 模板语法
存放于 templates 目录下的 html文件称之为模板文件,要返回的 html页面中的数据是动态的,那么必须在 html页面中嵌入变量,这便用到了Django 的模板语法。
模板语法
1、跟变量相关的都使用双括号 {{}}
2、跟逻辑相关的都使用 {% %}
3、模板文件中取值一律使用点语法
4、在模板文件里面的函数和类,不用加括号,会自动加括号调用, 不能传递参数
本质上:在HTML中写一些占位符,由数据对这些占位符替换和处理,原始数据怎么样,如果不做处理那么网页显示的数据就会是怎么样。
python中的列表取值,通过list[index],Django的模板语法取值字典的索引,通过点去操作
列表循环操作
字典循环操作
条件判断
- {% if 条件 %} 条件为真时 if 的子句才会生效,条件也可以是一个变量。
- if 会对变量进行求值,在变量值为空、或者视图没有为其传值的情况下均为 False。
- if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not 判断。
基于模板语法和爬虫的小练习
案例演示
# 视图层
def to_html(request):
name = '小满'
age = 3
score = 99.00
eva_score = 99.87
hobby = ['逃课', '欺负同学']
data = {'name': '大乔', 'hobby': ['欺负小满', '抢小满人头']}
is_single = True
is_beautiful = False
dislike = {'老夫子', '红buff又没了'}
like = ('阿珂', '海月')
def foo():
return '你是年少的欢喜'
class Hero:
name = '阿珂'
@property
def hobby(self):
return '欺负小满'
ak = Hero()
return render(request, 'app1/jinjia2.html', locals())
<!-- 前端网页 -->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hi~ o(* ̄▽ ̄*)ブ</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="{% static 'app1/css/jinjia2.css' %}">
<link href="https://fonts.googleapis.com/css2?family=Zhi+Mang+Xing&display=swap" rel="stylesheet">
<script src="{% static 'app1/js/fontawesome.js' %}"></script>
</head>
<body>
<p class="title">测试Jinjia2模板语法</p>
<div id="left">
<p>字符串<i class="fa-solid fa-arrow-right"></i>{{ name }}</p>
<p>整数<i class="fa-solid fa-arrow-right"></i>{{ age }}</p>
<p>浮点型(全是0)<i class="fa-solid fa-arrow-right"></i>{{ score }}</p>
<p>浮点型(常规)<i class="fa-solid fa-arrow-right"></i>{{ eva_score }}</p>
<p>列表<i class="fa-solid fa-arrow-right"></i>{{ hobby }}</p>
<p>字典<i class="fa-solid fa-arrow-right"></i>{{ data }}</p>
<p>布尔<i class="fa-solid fa-arrow-right"></i>{{ is_single }}</p>
<p>布尔<i class="fa-solid fa-arrow-right"></i>{{ is_beautiful }}</p>
<p>集合<i class="fa-solid fa-arrow-right"></i>{{ dislike }}</p>
<p>元组<i class="fa-solid fa-arrow-right"></i>{{ like }}</p>
</div>
<div id="middle">
<p class="on-right">遍历列表</p>
{% for item in hobby %}
<p>{{ item }}</p>
{% endfor %}
<hr>
<p class="on-right">遍历字典</p>
{% for item in data %}
<p>{{ item }}</p>
{% endfor %}
<hr>
<p class="on-right">遍历集合</p>
{% for item in dislike %}
<p>{{ item }}</p>
{% endfor %}
<hr>
<p class="on-right">遍历元组</p>
{% for item in like %}
<p>{{ item }}</p>
{% endfor %}
</div>
<div id="right">
<p>函数<i class="fa-solid fa-arrow-right"></i>{{ foo }}</p>
<p>类<i class="fa-solid fa-arrow-right"></i>{{ ak }}</p>
<p>类(通过.去获得属性)<i class="fa-solid fa-arrow-right"></i>{{ ak.name }}</p>
<p>类(通过.去获得方法)<i class="fa-solid fa-arrow-right"></i>{{ ak.hobby }}</p>
</div>
<div class="outer"></div>
<p class="title">小满三岁啦</p>
<img src="{% static 'app1/img/小满三岁啦.jpg' %}" alt="">
</body>
</html>
/* css */
body {
background-image: url(https://i.pinimg.com/564x/07/b0/45/07b045db2a74d50fbdea42539cc4ccbf.jpg);
}
p {
padding: 5px 0 0 15px;
font-size: 18px;
}
p.title {
font:700 4em 'Zhi Mang Xing';
text-align: center;
color: tomato;
text-decoration: underline 2px wavy green;
clear: both;
}
i {
padding: 0 10px 1px 10px;
display: inline-block;
color: red;
}
#left, #middle, #right {
float: left;
border: 1px solid tomato;
margin: 20px;
width: 30%;
}
#middle > hr {
border: 1px solid tomato;
}
#middle > .on-left {
float: left;
}
#middle > .on-right {
float: right;
padding: 10px;
}
img {
width: 359px;
float: right;
position: relative;
top: -440px;
right: 177px;
}
.outer {
width: 567px;
height: 300px;
float: right;
position: relative;
top: -17px;
right:82px;
border: 1px solid tomato;
}
模板语法之过滤器
类似于python里面的内置方法
语法:
{{变量|过滤器:参数}}
语法 | 说明 | 例子 |
---|---|---|
default | 如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值 | {{ value|default:"nothing"}} |
length | 返回值的长度,对字符串和列表都起作用。 | {{ value|length }} |
filesizeformat | 将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB' , '4.1 MB' , '102 bytes' , 等等)。 |
{{ value|filesizeformat }} |
date | 时间格式化,如果now=datetime.datetime.now() ,那么结果就算2024-03-02 01-03-32 |
{{ now|date:'Y-m-d H-m-s'}} |
slice | 切片,用法和python一样,支持步长,顾头不顾尾,比如字符串 text='你是年少的欢喜' 执行后面的将得到是年少 |
{{ text|slice:"2:5"}} |
truncatechars | 如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“…”)结尾。 | {{ sentence|truncatechars:"30"}} |
safe | 添加safe告诉Django不必转义 | {{p_tag|safe}} |
join | 字符串的拼接,被拼接的需要是一个序列,注意没用空格,hobby = ['逃课', '欺负同学'] 使用例子后的结果就算逃课.欺负同学 |
{{ hobby|join:"." }} |
add | 加法,很容易理解score=99 ,执行例子的结果就是109 |
{{ score|add:10 }} |
filesizeformat 案例
# 视图层函数内部
import os
from pathlib import Path
path = Path('app1/static/app1/img/小满三岁啦.jpg').absolute()
size_of_img = os.path.getsize(path)
<!-- 前端 -->
<div class="outer"></div>
<p class="title">小满三岁啦</p>
<img src="{% static 'app1/img/小满三岁啦.jpg' %}" alt="">
<p>路径地址为:{{ path }}</p>
<p>原始大小为:{{ size_of_img }} (单位字节)</p>
<p>格式化后的大小为:{{ size_of_img|filesizeformat }}</p>
# 结果
路径地址为:E:\djangoProject\mysite\app1\static\app1\img\小满三岁啦.jpg
原始大小为:87879 (单位字节)
格式化后的大小为:85.8 KB
truncatechars 案例
sentence = '我在爱情上的愚钝就像是门窗紧闭的屋子,' \
'虽然爱情的脚步在屋前走过去又走过来,我也听到了,' \
'可是我觉得那是路过的脚步,那是走向别人的脚步。' \
'直到有一天,这个脚步停留在这里。'
{{ sentence|truncatechars:"30"}}
# 原字符串
我在爱情上的愚钝就像是门窗紧闭的屋子,虽然爱情的脚步在屋前走过去又走过来,我也听到了,可是我觉得那是路过的脚步,那是走向别人的脚步。直到有一天,这个脚步停留在这里。
# 截断后
我在爱情上的愚钝就像是门窗紧闭的屋子,虽然爱情的脚步在屋前…
safe
Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。
p_tag = '<p>一屋两人三餐四季</p>'
{{ p_tag }}
{{ p_tag|safe }}
# 结果
<p>一屋两人三餐四季</p>
一屋两人三餐四季
make_safe
后端转义
from django.utils.safestring import mark_safe
p_tag = '<p>一屋两人三餐四季</p>'
p_tag = mark_safe(p_tag)
{{ p_tag }}
一屋两人三餐四季
其它过滤器(了解即可)
过滤器 | 描述 |
---|---|
upper | 以大写方式输出 |
add | 给value加上一个数值 |
addslashes | 单引号加上转义号 |
capfirst | 第一个字母大写 |
center | 输出指定长度的字符串,把变量居中 |
cut | 删除指定字符串 |
date | 格式化日期 |
default | 如果值不存在,则使用默认值代替 |
default_if_none | 如果值为None, 则使用默认值代替 |
dictsort | 按某字段排序,变量必须是一个dictionary |
dictsortreversed | 按某字段倒序排序,变量必须是dictionary |
divisibleby | 判断是否可以被数字整除 |
escape | 按HTML转义,比如将”<”转换为”<” |
filesizeformat | 增加数字的可读性,转换结果为13KB,89MB,3Bytes等 |
first | 返回列表的第1个元素,变量必须是一个列表 |
floatformat | 转换为指定精度的小数,默认保留1位小数 |
get_digit | 从个位数开始截取指定位置的数字 |
join | 用指定分隔符连接列表 |
length | 返回列表中元素的个数或字符串长度 |
length_is | 检查列表,字符串长度是否符合指定的值 |
linebreaks | 用或 标签包裹变量 |
linebreaksbr | 用 标签代替换行符 |
linenumbers | 为变量中的每一行加上行号 |
ljust | 输出指定长度的字符串,变量左对齐 |
lower | 字符串变小写 |
make_list | 将字符串转换为列表 |
pluralize | 根据数字确定是否输出英文复数符号 |
random | 返回列表的随机一项 |
removetags | 删除字符串中指定的HTML标记 |
rjust | 输出指定长度的字符串,变量右对齐 |
slice | 切片操作, 返回列表 |
slugify | 在字符串中留下减号和下划线,其它符号删除,空格用减号替换 |
stringformat | 字符串格式化,语法同python |
time | 返回日期的时间部分 |
timesince | 以“到现在为止过了多长时间”显示时间变量 |
timeuntil | 以“从现在开始到时间变量”还有多长时间显示时间变量 |
title | 每个单词首字母大写 |
truncatewords | 将字符串转换为省略表达方式 |
truncatewords_html | 同上,但保留其中的HTML标签 |
urlencode | 将字符串中的特殊字符转换为url兼容表达方式 |
urlize | 将变量字符串中的url由纯文本变为链接 |
wordcount | 返回变量字符串中的单词数 |
模板语法之循环序号
循环序号可以通过{{forloop}}显示
常用标签之 with 标签
with标签用来为一个复杂的变量名起别名,如果变量的值来自于数据库
在起别名后只需要使用别名即可,无需每次都向数据库发送请求来重新获取变量的值
{% with li.1.upper as v %}
{{ v }}
{% endwith %}
常用标签之 csrf_token 标签
当用form表单提交 POST 请求时必须加上标签{% csrf_token %},该标签用于防止跨站伪造请求
<form action="" method="POST">
{% csrf_token %}
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="password" name="pwd"></p>
<p><input type="submit" value="提交"></p>
</form>
# 具体工作原理为:
# 1 在GET请求到form表单时,标签{% csrf_token%}会被渲染成一个隐藏的input标签
# 该标签包含了由服务端生成的一串随机字符串,例如: <input type="hidden" name="csrfmiddlewaretoken" value="dmje28mFo...OvnZ5">
# 2 在使用form表单提交POST请求时,会提交上述随机字符串,服务端在接收到该POST请求时会对比该随机字符串
# 对比成功则处理该POST请求,否则拒绝,以此来确定客户端的身份
自定义标签之simple_tag
参考链接:https://www.liujiangblog.com/course/django/150
- 在当前app下建立一个名称叫做
templatetags
的文件夹,(只能叫这个名称),然后再给他新建一个__init__.py
里面可以不用写任何东西。- 在新建的文件夹下面,新建一个自定义过滤器的名称,比如
my_tag.py
- 后续的后端的逻辑代码都是放在这个
py
文件里面写的
自定义标签之inclusion_tag
# 自定义的py文件 位于tamplatetags文件夹下
# 如何制作inclusion_tag
# 1. 在当前APP下或根目录下创建一个文件夹 templatetags
# 2. 在当前文件夹下创建一个 py 文件 (名字随意)
# 3. 在py文件内部 首先要导入
from django import template
from blog import models
# 4. 创建一个注册对象 这里只能叫 register
register = template.Library()
# 5. 创建一个函数
# 函数的头顶上要用装饰器注册
# 参数是指定目录下的前端模板文件
@register.inclusion_tag('tags/adv.html')
def home_adv():
# 6. 声明需要在前端文件使用的数据
adv_data = models.Adv.objects.all().order_by('pk')
# 返回当前函数的名称空间
return locals()
<!-- 要渲染的模板文件 -->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="col-md-2">
<div class="thumbnail">
<img src="{% static 'img/代码猫.jpg' %}" alt="代码猫">
<h3>Opps~</h3>
<p class="code-secret">写代码不加班的秘密竟然是...</p>
<br>
<p>
<a href="https://api.52vmy.cn/api/wl/moyu" target="_blank" class="btn btn-primary btn-block" role="button">点我了解</a>
<button class="btn btn-danger btn-block">关闭广告</button>
</p>
</div>
</div>
</body>
</html>
{# 使用inclusion_tag #}
{# 第一步 加载 load py文件名 #}
{% load CommonInclusionTags %}
{# 第二步 使用 就是加载的py文件下面定义的函数名 #}
{% home_adv %}
模板的继承
开发中,模板文件彼此之间可能会有大量冗余代码,为此Django 提供了专门的语法来解决这个问题,主要围绕三种标签的使用:
- include 标签
- extends 标签
- block 标签
模板的导入之 include 标签
作用: 在一个模板文件中,引入/重用另外一个模板文件的内容
{% include '模版名称' %}
模板的继承\派生之extends标签、block标签
作用: 在一个模板文件中,引入/重用另外一个模板文件的内容
也就是说include 有的功能extends 全都有,但是extends可以搭配一个block标签,用于在继承的基础上定制新的内容
Django模版引擎中最复杂且最强大的部分就是模版继承了。
创建一个基本的“骨架”模版,它包含站点中的全部元素,并且可以定义多处blocks 。(block标签的内容替换或更新)
总结与注意
标签 extends 必须放在首行,html 文件中 block 越多可定制性越强
include 仅仅只是完全引用其他模板文件,而 extends 却可以搭配 block 在引用的基础上进行扩写
变量 {{ block.super }} 可以重用父类的内容,然后在父类基础上增加新内容,而不是完全覆盖
在一个模版中不能出现重名的 block 标签。
为了提升可读性,我们可以给标签 {% endblock %} 起一个名字例如: {% block content %} ...
本文作者:小满三岁啦
本文链接:https://www.cnblogs.com/ccsvip/p/18090671
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。