Python Web框架--框架Flask--模板Jinja(三

2019-12-11  本文已影响0人  无剑_君

一、模板简介

Jinja 模板的使用方法。

  1. 模板标签
      其实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>
  1. 继承
    模板可以继承其他模板,我们可以将布局设置为父模板,让其他模板继承,这样可以非常方便的控制整个程序的外观。
    例如:这里有一个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 %}
  1. 控制流
    条件判断可以这么写,类似于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

  1. 在模板渲染中,使用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
  1. 应用全局对象
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()将会被自动调用
  1. 请求上下文生命周期
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对象。

上一篇 下一篇

猜你喜欢

热点阅读