2.jinja2
2024-10-20 05:22:45
1.jinja2模板介绍和查找路径
from flask import Flask, render_template import os # 之前提到过在渲染模板的时候,默认会从项目根目录下的templates目录下查找模板 # 如果不想把模板文件放在templates文件夹下,那么可以在Flask初始化的时候指定 ''' Flask类的构造函数 def __init__( self, import_name, static_url_path=None, static_folder='static', static_host=None, host_matching=False, subdomain_matching=False, template_folder='satori', instance_path=None, instance_relative_config=False, root_path=None ): 可以看到有一个template_folder='satori' 我们在初始化的时候可以重新指定 ''' BASE_DIR = os.path.dirname(__file__) app = Flask(__name__, template_folder=os.path.join(BASE_DIR, "satori")) @app.route(r"/satori") def satori(): return render_template("1.html") if __name__ == '__main__': app.run(host="localhost", port=7777)
2.模板传参以及技巧
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>my name is {{name}}, age is {{age}}</h1> </body> </html>
from flask import Flask, render_template app = Flask(__name__) @app.route(r"/index") def index(): ''' 在html文件中,以{{}}定义,比如{{name}},然后在渲染模板的时候传参进去即可 通过name="xxx"的形式,会自动进行替换。 渲染的流程是先把html文件读取进来,再将{{}}里面的内容替换掉,因此最终返回给浏览器的内容是不包含{{}}的 ''' return render_template("1.html", name="satori", age=17) if __name__ == "__main__": app.run(host="localhost", port=8888)
@app.route(r"/index") def index(): ''' 但是如果要替换的内容比较多的话,那么一个一个写的话,风格不是很pythonic 因此我们会把内容都写在一个字典里,然后通过**传值 ''' replace_content = {"name": "mashiro", "age": 16} return render_template("1.html", **replace_content)
依旧可以打印出结果
既然如此的话,那么我们可不可以传入一个字典或者列表呢呢?然后按照key或者索引的方式呢?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--可以使用Python的语法d["xx"], 也可以使用d.xx--> <h2>my name is {{info['name']}}, age is {{info.age}}</h2> <h2>在{{arr}}中,数字1总共出现了{{arr.count(1)}}次</h2> <h2>另外两个花括号之间必须要写值,不能是空的花括号,否则报错</h2> <h2>但如果两个花括号中间的内容,我们在模板渲染的时候没有传值呢,那么不会显示,也不会报错</h2> <h2>比如下面的类容就不会显示,因为在render_template中没有mmp="xx"</h2> <h2>{{mmp}}</h2> </body> </html>
from flask import Flask, render_template app = Flask(__name__) @app.route(r"/index") def index(): ''' 但是如果要替换的内容比较多的话,那么一个一个写的话,风格不是很pythonic 因此我们会把内容都写在一个字典里,然后通过**传值 ''' info = {"name": "matsuri", "age": 400} arr = [1, 1, 2, 3, 1, 1, 3] return render_template("1.html", info=info, arr=arr) if __name__ == "__main__": app.run(host="localhost", port=8888)
3.模板中使用url_for的两种方式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2><a href="{{link}}">你想成为女装大佬吗?想搞基吗?想的话,就点击进入新世界的大门吧</a></h2> </body> </html>
from flask import Flask, render_template, url_for app = Flask(__name__) @app.route(r"/bili") def bili(): import requests content = requests.get("http://www.bilibili.com") content.encoding = content.apparent_encoding return content.text @app.route(r"/gay") def gay(): return render_template("bilibili.html", link=url_for("bili")) if __name__ == "__main__": app.run(host="localhost", port=8888)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2><a href="{{ url_for('bili') }}">你想成为女装大佬吗?想搞基吗?想的话,就点击进入新世界的大门吧</a></h2> </body> </html>
from flask import Flask, render_template, url_for app = Flask(__name__) @app.route(r"/bili") def bili(): import requests content = requests.get("http://www.bilibili.com") content.encoding = content.apparent_encoding return content.text @app.route(r"/gay") def gay(): # 替换之后,这里就不用传参了,因为在模板中可以直接获取链接 return render_template("bilibili.html") if __name__ == "__main__": app.run(host="localhost", port=8888)
同样的结果
4.jinja2模板过滤器的基本使用
过滤器是通过管道符号|,来进行使用的,例如:{{name|length}},将返回name的长度。过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器根据自己的功能再返回相应的值,之后再将结果渲染到页面中。jinja2内置了许多过滤器,下面来介绍一个常用的过滤器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{age|abs}}</h1> </body> </html>
@app.route(r"/filter") def foo(): # 这里传入一个负值 return render_template("filter.html", age=-18)
5.default过滤器详解
之前我们说过,如果我们定义了一个{{mmp}},但是我们在视图函数的render_template中并没有传值,那么{{mmp}}在页面上是不会显示的,当然也不会报错。但是我们想,对于那些没有传值的变量,我们能不能给一个默认值呢?显然是可以的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>{{s1|default("这个人很懒,什么也没留下")}}</h2> <h2>{{s2|default("这个人很懒,什么也没留下")}}</h2> </body> </html>
@app.route(r"/signature") def info(): s1 = "一个人只要好好活着,就足以拯救某个人" return render_template("defualt.html", s1=s1)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>{{s1}}</h2> <!--不过这里还有一个问题,那么如果我指定了s2=None,那么页面上就会显示None default是否执行,不在于你传的什么值,而在于你有没有传值,只要传了,就不会显示default的内容 那如果我想,当传入空字符串,空字典等等,在Python中为False的值,还是执行default的内容, 该怎么办呢?可以加入一个参数boolean=True,表示在Python中bool为False的值也会被包含在内--> <h2>{{s2|default("这个人很懒,什么也没留下", boolean=True)}}</h2> <!--如果s3为False,那么会自动选择"默认值",两种方式比较类似--> <h2>{{s3 or "默认值"}}</h2> </body> </html>
6.常用过滤器
escape:转义,默认是开启的。{{xxx|escape}}
那么如何关闭转义呢?这里要介绍一下{{}}和{% %},{{}}存放变量,{%%}执行逻辑
{% autoescape off %}
这里的标签是不会被转义的
{% endautoescape %}
safe:和escape相反,意思是安全的。{xxx|safe}也不会被转义
first:{xx|first},返回序列xx的第一个元素,我们也可以直接使用{{xx[0]}}
last:返回最后一个元素
length:返回序列的长度,sum:返回序列的总和
join:{xx|join(sep)},使用sep将序列xx拼接成一个字符串
int:转化为int
float:转化为float
string:转化为str
lower:小写
upper:大写
replace:{xx|replace(old, new)},将xx中old替换成new
truncate:{xx|truncate(length=14)},表示不管你输入多少字符,在页面上最多显示14和,剩下的用几个省略号表示
wordcounts:计算一个长字符串中某单词出现的次数
7.自定义过滤器
之前说过过滤器本质上就是个函数,因此我们只需要写个函数,定义相应的逻辑,然后把函数注册到jinja2过滤器当中即可
我们手动实现以下replace过滤器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>{{s|屮艸芔茻}}</h2> </body> </html>
@app.route(r"/index") def index(): s = "hello satori" return render_template("default.html", s=s) # 仅仅是这样是不起作用的,我们必须要将函数注册到jinja2过滤器当中 @app.template_filter(name="屮艸芔茻") # 这里的name就是我们在html中使用的过滤器的名字 def cut_hello(string): return string.replace("hello", "")
8.自定义过滤器处理时间
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>hello 大家好 我是lex,,发表时间:{{time| handle_time}}</p> </body> </html>
@app.route(r"/status") def publish(): import datetime time = datetime.datetime(2018, 9, 24) return render_template("status.html", time=time) @app.template_filter(name="handle_time") def handle_time(time): from datetime import datetime if isinstance(time, datetime): now = datetime.now() # 更精确的话可以使用秒 days = (now - time).days if days < 1: return "今天" elif days < 3: return "三天内" elif days < 7: return "一星期内" elif days < 30: return "一个月内" else: return "时间很久远了" else: # 返回的不是时间格式 return time
9.if语句
和Python中的if语句类似,使用{%%}包裹,但是不要忘记结尾的{%endif%}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% if gender == "f" %} <!--这里相当于Python的两层if循环--> {% if age >= 18 %} <h2>获取我们可以来一场交易</h2> {% else %} <h2>虽然担些风险但也值得一试</h2> {% endif %} {%else%} {% if age >= 18 %} <h2>我不搞基</h2> {% else %} <h2>可爱的男孩子也是可以的</h2> {% endif %} {%endif%} </body> </html>
@app.route(r"/deal") def deal(): return render_template("if.html", gender="f", age=16)
10.for语句
和Python里面for循环也基本一致,也别忘了结尾的{% endfor %}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% for age in ages %} <h2>{{age}}</h2> {% endfor %} <table border="1px solid red"> <thead> <tr> <th>姓名</th> <th>出场动漫</th> </tr> </thead> <tbody> {% for name in girls %} <tr> <td>{{name}}</td> <td>{{girls[name]}}</td> </tr> {% endfor %} </tbody> </table> </body> </html>
@app.route(r"/for") def loop(): ages = [17, 400, 20, 16, 14] girls = {"古明地觉": "东方地灵殿", "四方茉莉": "sola", "牧濑红莉栖": "命运石之门", "坂上智代": "Clannad", "神尾观铃": "air"} return render_template("for.html", ages=ages, girls=girls)
如果想反向遍历,只需要加上一个过滤器,xx|reverse,表示反向遍历xx
此外,jinja2还提供了索引
loop.index 当前迭代的索引(从1开始)
loop.index0 当前迭代的索引(从0开始)
loop.first 是否是第一次迭代,返回True或者False
loop.last 是否是最后一次迭代,返回True或者False
loop.length 序列的长度
我们对刚才的例子做一下修改
11.九九乘法表
在jinja2中,还可以使用range,接下来便实现一个九九乘法表
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table border="1px"> {% for i in range(1, 10) %} <tr> <!--此外还有一种方式,那就是jinja2中,for循环是可以带条件的,这句话还可以这么改--> <!--{# {% for j in range(1, 10) if j < i %}, j也从1遍历到10,但必须满足j < i #}--> <!--关于上面的{# #}在jinja中表示注释,html的注释没用,还是会被解释,必须要在模板语言两端加上{# #} --> {% for j in range(1, i) %} <td>{{j}} * {{i}} = {{i * j}}</td> {% endfor %} </tr> {% endfor %} </table> </body> </html>
@app.route(r"/nine9c法b") def minus(): return render_template("九九乘法表.html")
12.宏的概念和基本使用
宏,说的通俗一点,就类似于Python当中的函数,我们给一系列操作进行一个封装,再给一个名字。然后调用宏名的时候,就会执行封装的一系列操作。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--如何定义一个宏--> {% macro input(name, value="", type="text") %} <input type="{{type}}" name="{{name}}" value="{{value}}"/> {% endmacro %} <!--input就类似于函数名,这里叫什么无所谓。name是我们需要传的参数,value和type是缺省参数--> <!--当我们执行{# {{input("satori", "love")}} #}的时候,等价于<input type="text" name="satori" value="love"/>--> <form action="/show" method="post"> {{input("satori","东方地灵殿")}} {{input("mashiro","樱花庄的宠物女孩")}} {{input("", "提交", "submit")}} </form> </body> </html>
from flask import Flask, render_template, request app = Flask(__name__) @app.route(r"/index") def index(): return render_template("1.html") @app.route(r"/show", methods=["POST"]) def show(): satori = request.form.get("satori") mashiro = request.form.get("mashiro") return f"satori come from {satori}, mashiro come from {mashiro}" if __name__ == "__main__": app.run(host="localhost", port=8888)
13.宏的导入和注意事项
宏也是可以导入的,在flask中,宏的导入和Python导入模块是类似的。话说为什么要有宏的导入,和Python中模块的导入是一致的。不然文件看起来很乱
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% macro input(name, value="", type="text") %} <input type="{{type}}" name="{{name}}" value="{{value}}"/> {% endmacro %} </body> </html>
我把之前定义的宏写在一个单独的文件里,导入通过import "宏文件的路径" as xxx, 通过xxx.宏名即可,这里必须要起名字
或者from "宏文件的路径" import 宏名 [as xxx]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--导入的同时指定一个别名--> {% import "macro.html" as macro %} <form action="/show" method="post"> <!--使用的时候直接通过marco.input即可。marco相当于模块,input相当于函数或者类--> {{macro.input("satori","东方地灵殿")}} {{macro.input("mashiro","樱花庄的宠物女孩")}} {{macro.input("", "提交", "submit")}} </form> </body> </html>
14.include标签使用
include的使用非常简单,直接导入就行了,{% include "xx.html" %},相当于 ctrl+c和ctrl+v
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>但使龙城飞将在</p> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% include "a.html" %} <p>不教胡马度阴山</p> </body> </html>
15.set和with语句以及模板中定义变量
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% set username="satori" %} <!--set一旦设置了,那么在全局都可以使用--> <h2>{{username}}</h2> {% with username="koishi" %} <h2>{{username}}</h2> {% endwith %} <!--{#with一旦设置,那么设置的值只会在with语句块内生效,所以结尾才要有endwith构成一个快 此外with还有另一种写法,那就是 {% with %} {% set username = "koishi" %} {% endwith %} 这样写也是没问题的,因为set在with里面 #}--> <h1>{{username}}</h1> </body> </html>
16.加载静态文件
需要在项目根目录下,创建一个static文件夹,当然也可以不叫static,但是flask默认叫static。当然我们也可以在创建app的时候单独指定static_folder,类似template_folder
p{ color: aqua; }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="{{url_for('static', filename='css/index.css')}}"> </head> <body> <p>xxxxxxxxxxxxxxxx</p> </body> </html>
@app.route(r"/index") def index(): return render_template("index.html")
一句话总结:无论图片啊,js啊,还是css,都使用使用{{url_for('static', filename='css|js|images/xxx.xxx')}}
17.模板继承
之前介绍了include,但是还不够灵活,因为网站一大的话,那么重合的部分就会变多,因此使用include还不是一个最好的方式。接下来介绍的模板继承非常的灵活。可以想象一下,我们博客园,四周很多内容都是不变的,如果没来一个页面都要写一遍的话,会很麻烦。因此我们可以将不变的部分先写好,在变的部分留一个坑,这就是父模板。然后字模板继承的时候,会将父模板不变的部分继承过来,然后将变得部分,也就是父模板中挖的坑填好。总结一下就是:父模板挖坑,子模板填坑。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>なんでそんなになれてんだよ</p> <p>雪菜と何度もキースしたんだよ</p> {% block 冬马小三 %} {% endblock %} <!--这两行便相当于我们在父模板中挖的坑--> <p>どこまで私を置いてきぼりに気が済むんだよ</p> {% block 雪菜碧池 %} {% endblock %} <p>最初私の前から消えたのはお前だろ</p> {% block 打死白学家 %} {% endblock %} <p>勝手に私の手が届けないところに行ったのはお前だろう</p> </body> </html>
{% extends "base.html" %} <!--将父模板继承过来--> <!--接下来填好我们在父模板中挖的坑,我们挖了三个,所以这里也应该要埋三个--> {% block 冬马小三 %} <h2>我爱小三</h2> {% endblock %} {% block 雪菜碧池 %} <h2>我爱碧池</h2> {% endblock %} {% block 打死白学家 %} <h2>打死春哥,悄悄抱走冬马和雪菜</h2> {% endblock %}
@app.route(r"/dsxb") def dsxb(): return render_template("dsxb.html")
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--另外模板继承,如果父模板中挖的坑中,已经有内容了,那么子模板继承过来的时候会自动清除。--> <!--{# 如果想保留,需要加上{{super()}} #}--> {% block 冬马小三 %} <p>我是父模板中的内容</p> {% endblock %} {% block 雪菜碧池 %} {% endblock %} </body> </html>
{% extends "base.html" %} {% block 冬马小三 %} {{super()}} <h2>我是子模板中的内容</h2> {% endblock %} <!--{# 如果在一个块中,想使用另一个块的内容,可以通过{{self.块名()}}来实现 #}--> {% block 雪菜碧池 %} {{self.冬马小三()}} {% endblock %}
注意:{% extend "xxx.html" %}要放在最上面,不然容易出问题,在Django中是直接会报错的
另外,子模板中的代码一定要放在block语句块内,如果放在了外面,jinja是不会渲染的
最新文章
- tagfield
- SQL Server 2005 镜像构建手册
- Python3 - 时间处理与定时任务
- Android 设置界面的圆角选项
- redis 缓存技术与memcache的最大差别
- ExtJs目录说明
- Angular规范
- python学习之路二(字符串,字典,序列和元组)
- easyUI 添加排序到datagrid
- POJ1273(最大流)
- 18 Loader代码案例
- ASP Action函数 如何接收client传递的数据(编辑中。。。)
- 部署自建CA颁发证书实现https加密
- servlet(3)
- google的Python风格规范
- [dpdk] TSC , HPET, Timer, Event Timer,RDTSCP
- Python基础_私有变量访问限制
- Android WebView清空缓存
- .net如何处理高并发socket,建立高性能健壮的socket服务
- traceroute命令详解
热门文章
- Win10下Pytorch的安装和使用[斗之力三段]
- static 关键字解析(转)
- Python中enumerate函数用法详解
- 最短路径——Dijkstra算法以及二叉堆优化(含证明)
- Windows IRP
- Windows关机过程分析与快速关机
- [Leetcode] Longest consecutive sequence 最长连续序列
- [Leetcode] Populating next right pointer in each node ii 填充每个节点的右指针
- 解析Mybaits的insert方法返回数字-2147482646的原因
- LaTeX的图片插入及排版[转]