Flask-day4
自定义过滤器"response值|过滤器名称"
@app.template_filter(“times”)
app.py
from datetime import datetime
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def index():
context = {
"create_time": datetime(2020,4,13,10,2,40), # response的值
}
return render_template("index.html",**context)
# print((datetime.now()-datetime(2020,4,13,10,2,40).)
print(datetime(2020,4,13,10,2,40))
now = datetime.now()
time1 = datetime(2020,4,13,10,2,40)
print((now-time1).total_seconds())
@app.template_filter("time_filter") #过滤器
def handle_time(time): #过滤器是一个函数
if isinstance(time,datetime):
now = datetime.now()
timestamp = (now - time).total_seconds()
if timestamp < 60:
return "刚刚"
elif timestamp>=60 and timestamp < 60*60:
minutes = timestamp/60
return "%s分钟前"% int(minutes)
elif timestamp>=60*60 and timestamp < 60*60*24:
hours = timestamp/(60*60)
return "%s小时前" % int(hours)
elif timestamp >= 60*60*24 and timestamp <60*60*24*30:
days = timestamp/(60*60*24)
return "%s天前"%int(days)`
else:
return time.strftime("%Y-%m-%d %H:%M:%S")
else:
return time
if __name__ == '__main__':
app.run()
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是一篇文章</h1>
<p>发表时间:{{ create_time | time_filter }}</p> #time_filter是自定义过滤器
</body>
</html>
访问index.html,向服务器request.app.py返回create_time,index.html request此值并调用过滤器.
自动转义(模板中:{%autoescape false%})
转义的概念是,在模板渲染字符串的时候,字符串有可能包括一些非常危险的字符比如<
、>
等,这些字符会破坏掉原来HTML
标签的结构,更严重的可能会发生XSS
跨域脚本攻击,因此如果碰到<
、>
这些字符的时候,应该转义成HTML
能正确表示这些字符的写法,比如>
在HTML
中应该用<
来表示等。
但是Flask
中默认没有开启全局自动转义,针对那些以.html
、.htm
、.xml
和.xhtml
结尾的文件,如果采用render_template
函数进行渲染的,则会开启自动转义。并且当用render_template_string
函数的时候,会将所有的字符串进行转义后再渲染。而对于Jinja2
默认没有开启全局自动转义,作者有自己的原因:
- 渲染到模板中的字符串并不是所有都是危险的,大部分还是没有问题的,如果开启自动转义,那么将会带来大量的不必要的开销。
Jinja2
很难获取当前的字符串是否已经被转义过了,因此如果开启自动转义,将对一些已经被转义过的字符串发生二次转义,在渲染后会破坏原来的字符串。
在没有开启自动转义的模式下(比如以.conf
结尾的文件),对于一些不信任的字符串,可以通过{{ content_html|e }}
或者是{{ content_html|escape }}
的方式进行转义。在开启了自动转义的模式下,如果想关闭自动转义,可以通过{{ content_html|safe }}
的方式关闭自动转义。而{%autoescape true/false%}...{%endautoescape%}
可以将一段代码块放在中间,来关闭或开启自动转义,例如以下代码关闭了自动转义:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是一篇文章</h1>
<p>发表时间:{{ create_time | time_filter }}</p>
弹出代码位置:
{% autoescape false %} # 取消转义
{{ beng }}
{% endautoescape %}
</body>
</html>
@app.route('/')
def index():
context = {
"create_time": datetime(2020,4,13,10,2,40),
"beng":"<script>alert('hi')</script>" #包含script,默认是被转义的
}
return render_template("index.html",**context)
有些html代码需要转义,如script代码,有时不需要转义,如加粗等.
宏macros和import宏
模板中的宏跟python中的函数类似,可以传递参数,但是不能有返回值,可以将一些经常用到的代码片段放到宏中,然后把一些不固定的值抽取出来当成一个变量,以下将用一个例子来进行解释,该例使用宏来创建3个不同的:
定义宏macros.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% macro createInput(type,name="",value="")%} # 定义宏
<input type="{{ type }}",name="{{ name }}",value="{{ value }}">
{% endmacro %}
</body>
</html>
应用宏index.html:
{% import "macros.html" as macro%} #导入宏
<!-- 或者:{% from "macros.html" import createInput as inp %} -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>macros:</p>
<form action="" method="get">
用户:{{ macro.createInput(type="text",name="username",value="abc") }} #创建第一个input
密码:{{ macro.createInput(type="password",name="password") }} #创建第二个表单
{{ macro.createInput(type="submit",name="submit",value="提交") }} # 创建第三个表单
</form>
</body>
</html>
可见,宏是模板中的宏,一般是定义一个macros.html用于存放各种宏方法,再在各模板中导入该宏,使用该方法.
模板中的include
include可以将常用的网页部分(如head和foot)做成head.html和foot.html,在某一网页中包含它们即可.这是一个模板上用的,一般将head.html和foot.html放在templates目录下的common目录:
head.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
</body>
</html>
foot.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</body>
</html>
要引用的网页如include.html:
{% include "common/head.html" %} #包含head.html
<h1>这是中间内容</h1>
{% include "common/foot.html" %} #包含foot.html
include.html页面就会显示head.html+自己的内容+foot.html
可见include方法是使用在模板中的.
继承extends
继承是模板中的网页继承自某个base.html,base.html指定可以编辑的部分。
base.html(一般位于common目录下):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{% block title %} #这是命名为title的block
这是一个基类网页
{% endblock %}</h1>
<p>base.html位于common目录下</p>
<p>使用方法:{% block fangfa%} from base {% endblock %}</p> #这是命名为fangfa的block
</body>
</html>
page1.html(继承base.html):
{% extends "common/base.html" %} #继承base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% block title %} #在base.html的基础上修改title
这是一个测试网页1
{% endblock %}
{% block fangfa %} #在base.html的基础上-
<h1>这是测试网页的介绍方法</h1> -增加的内容
{{ super() }} #base.html定义的内容
{% endblock %}
</body>
</html>
static目录
在flask目录中新建static目录,右键将其设为sources root
开发网站时将js,css,images等静态资源放在此处。
使用时,在模板中用url_for调用即可,如=={{url_for(“static”,filename=“yellow-girl.jpg”)}}==
{% extends "common/base.html" %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% block title %}
这是一个测试网页1
<img src="{{ url_for("static",filename="yellow-girl.jpg")}}"> #图片是static目录下的yellow-girl.jpg
{% endblock %}
</body>
</html>