一、模板简介
Jinja 模板的使用方法。
- 模板标签
其实Jinja 模板和其他语言和框架的模板类似,反正都是通过某种语法将HTML文件中的特定元素替换为实际的值。如果使用过JSP、Thymeleaf 等模板,应该可以非常容易的学会使用 Jinja模板。
其实从上面的例子中我们应该可以看到Jinja 模板的基本语法了。代码块需要包含在{% %}块中,例如下面的代码。
{% extends 'layout.html' %}
{% block title %}主页{% endblock %}
{% block body %}
<div class="jumbotron">
<h1>主页</h1>
</div>
{% endblock %}
双大括号中的内容不会被转义,所有内容都会原样输出,它常常和其他辅助函数一起使用。
<a class="navbar-brand" href={{ url_for('index') }}>Flask小例子</a>
- 继承
模板可以继承其他模板,我们可以将布局设置为父模板,让其他模板继承,这样可以非常方便的控制整个程序的外观。
例如:这里有一个layout.html模板,它是整个程序的布局文件。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap.css') }}"/>
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap-theme.css') }}"/>
</head>
<body>
<div class="container body-content">
{% block body %}{% endblock %}
</div>
<div class="container footer">
<hr>
<p>这是页脚</p>
</div>
<script src="{{ url_for('static',filename='js/jquery.js') }}"></script>
<script src="{{ url_for('static',filename='js/bootstrap.js') }}"></script>
</body>
</html>
其他模板可以这么写。对比一下面向对象编程的继承概念,我们可以很容易的理解。
{% extends 'layout.html' %}
{% block title %}主页{% endblock %}
{% block body %}
<div class="jumbotron">
<h1>主页</h1>
<p>本项目演示了Flask的简单使用方法,点击导航栏上的菜单条查看具体功能。</p>
</div>
{% endblock %}
- 控制流
条件判断可以这么写,类似于JSP标签中的Java 代码,{% %}中也可以写Python代码。下面是Flask官方文档的例子。
<div class=metanav>
{% if not session.logged_in %}
<a href="{{ url_for('login') }}">log in</a>
{% else %}
<a href="{{ url_for('logout') }}">log out</a>
{% endif %}
</div>
循环的话可以这么写,和在Python中遍历差不多。
<tbody>
{% for key,value in data.items() %}
<tr>
<td>{{ key }}</td>
<td>{{ value }}</td>
</tr>
{% endfor %}
<tr>
<td>文件</td>
<td></td>
</tr>
</tbody>
需要注意不是所有的Python代码都可以写在模板里,如果希望从模板中引用其他文件的函数,需要显式将函数注册到模板中。
二、Flask Markup 上下文,request
- 在模板渲染中,使用Markup转换变量中的特殊字符
from flask import Markup
Markup函数对字符串进行转移处理再传递给render_template()函数
在浏览器中显示标签代码。
三、路由地址的反向生成
通过函数名获得与其绑定的Url地址
需要使用url_for函数进行反向解析
with app.text_request_context()
print(url_for('f_root')) # 输出:/
app.text_request_context()方法告诉解释器为在其作用域中的代码模拟一个HTTP请求上下文,使其好像被一个HTTP请求所调用。
四、使用Context上下文
它是服务器端获得应用及请求相关信息的对象。
1、会话上下文
会话(session)是一种客户端与服务器端保持状态的解决方案,会话上下文是用来实现这种解决方案的存储结构。
from flask import Flask,session
from datetime import datetime
app = Flask(__name__)
app.secret_key = 'SET_ME_BEFORE_USE_SESSION'
@app.route('/')
def hello_world():
return 'Hello World!'
@app.route('/write_session')
def wirteSession():
session['key_time']=datetime.now().strftime('%Y-%m-%d %H:%M:%S')# 将当前时间保存在Session中
return session['key_time'] # 返回当前时间
@app.route('/read_session')
def readSession():
return session.get('key_time')# 获取上次调用wirteSession时写入的时间并返回
除了正常的数据保存和读取,flask.session对象还维护自身的状态,通过new 判断本次请求的Session是否时新建的。
modified 判断本次请求中是否修改过Session键值。
@app.route('/write_session')
def wirteSession():
session['key_time']=time.time() # 将当前时间保存在Session中
return session.modified # 因为之前进行了Session设置,所以判断本次请求是否被修改过(modified)返回TRUE
- 应用全局对象
from flask import Flask,g
class MYDB():
def __init__(self):
print('一个数据库链接已经建立')
def close(self):
print('数据库已经关闭')
def connect_to_database():
return MYDB()
def get_db():
db = getattr(g,'_database',None)
if db is None:
db = connect_to_database()
g._database = db # 存入Flask.g对象中
return db
@app.teardown_request # 在请求结束时自动被Flask框架调用
def teardown_db(response):
db = getattr(g,'_database',None)# 从Flask.g对象中获取对象,检查是否有链接数据库对象,如果有则关闭
if db is not None:
db.close()
可以在请求处理函数的任何地方调用get_db()
class MYDB():
def __init__(self):
print('一个数据库链接已经建立')
def close(self):
print('数据库已经关闭')
def connect_to_database():
return MYDB()
def get_db():
db = getattr(g,'_database',None)
if db is None:
db = connect_to_database()
g._database = db # 存入Flask.g对象中
return db
@app.teardown_request
def teardown_db(response):
db = getattr(g,'_database',None)# 从Flask.g对象中获取对象
if db is not None:
db.close()
def login():
db=get_db() # 第一次调用getdb 创建数据库链接
session['has_login']=True
# 使用db检查数据库中的用户名和密码
def view_list():
if 'has_login' not in session:
login()
db = get_db() # 第二次调用get_db()# 直接复用之前建立的链接
# 使用db 从数据库查询数据,返回teardown_db()将会被自动调用
- 请求上下文生命周期
from flask import Flask, g, request
app = Flask(__name__)
@app.before_request
def before_request():
print 'before request started'
print request.url
@app.before_request
def before_request2():
print 'before request started 2'
print request.url
g.name="SampleApp"
@app.after_request
def after_request(response):
print 'after request finished'
print request.url
response.headers['key'] = 'value'
return response
@app.teardown_request
def teardown_request(exception):
print 'teardown request'
print request.url
@app.route('/')
def index():
return 'Hello, %s!' % g.name
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
访问”http://localhost:5000/”后,会在控制台输出:
before request started
http://localhost:5000/
before request started 2
http://localhost:5000/
after request finished
http://localhost:5000/
teardown request
http://localhost:5000/
request对象只有在请求上下文的生命周期内才可以访问。离开了请求的生命周期,其上下文环境也就不存在了,自然也无法获取request对象。而上面介绍的几个由上下文装饰器修饰的Hook函数,会挂载在请求生命周期内的不同阶段,所以其内部可以访问request对象。
网友评论