Flask修炼——模板!



内容概述:
to_python、to_url,
异常捕获,
请求钩子,
获取请求参数,
状态保持,
上下文,
Flask-Script 扩展,
模板


to_python、to_url

自定义转换器

to_python: 可以对匹配到的参数进行处理并返回,在调用视图函数前执行

to_url :在使用 url_for 的时候,对视图函数传的参数进行处理,处理完毕之后以便能够进行路由匹配




异常捕获

HTTP异常主动抛出

abort 方法:抛出一个给定状态代码的 HTTPException 或者 指定响应,例如想要用一个页面未找到异常来终止请求,你可以调用 abort(404)。

参数:code——HTTP 的错误状态码

捕获错误

errorhandler 装饰器 :注册一个错误处理程序,当程序抛出指定错误状态码的时候,就会调用该装饰器所装饰的方法

参数: code_or_exception – HTTP的错误状态码或指定异常

from flask import Flask
from flask import abort

app = Flask(__name__)


@app.route('/')
def index():
    return 'index'


@app.route('/demo1')
def demo1():
    # 主动抛出 HTTP 指定错误代码
    # abort(404)
    a = 0
    b = 1 / a
    return 'demo1'


@app.errorhandler(404)
def page_not_found(error):
    return "页面不见了~"


@app.errorhandler(ZeroDivisionError)
def zero_division_error(error):
    return "除数不能为0 "


if __name__ == '__main__':
    app.run(debug=True)



请求钩子

在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理 ,为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设施的功能,即请求钩子 .

请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子:

before_first_request: 在第一次请求之前会执行
before_request : 在每次请求之前会执行,可以在这里对一些非法的请求进行阻止,那么视图函数将不再被调用
after_request: 在请求之后会执行,并且函数里面接收一个参数:响应,还需要将响应进行返回
teardown_request: 在请求之后会执行,如果请求的函数有异常,会把具体异常抛出

from flask import Flask


app = Flask(__name__)


@app.before_first_request
def before_first_request():
    """在第一次请求之前会访问该函数"""
    print('before_first_request')


@app.before_request
def before_request():
    """在每次请求之前会访问该函数"""
    print('before_request')
    # 可以对一些非法的请求进行阻止
    # if 如果ip在黑名单:
    #   return "在黑名单中"


@app.after_request
def after_request(response):
    """在请求之后会调用,并且函数里面接收一个参数:响应,还需要将响应进行返回"""
    print('after_request')
    return response


@app.teardown_request
def teardown_request(error):
    """在请求之后会执行,如果请求的函数报有异常,会把具体异常传入到此函数"""
    print('teardown_request')


@app.route('/')
def index():
    return 'index'


if __name__ == '__main__':
    app.run(debug=True)
装饰器路由的实现

Flask有两大核心:Werkzeug和Jinja2

- Werkzeug实现路由、调试和Web服务器网关接口
- Jinja2实现了模板。



获取请求参数

request:

request 就是flask中代表当前请求的 request 对象,其中一个请求上下文变量(理解成全局变量,在视图函数中直接使用可以取到当前本次请求)

常用的属性如下:

属性 说明 类型
data 记录请求的数据,并转换为字符串 *
form 记录请求中的表单数据 MultiDict
args 记录请求中的查询参数 MultiDict
cookies 记录请求中的cookie信息 Dict
headers 记录请求中的报文头 EnvironHeaders
method 记录请求使用的HTTP方法 GET/POST
url 记录请求的URL地址 string
files 记录请求上传的文件 *
from flask import Flask
from flask import request

app = Flask(__name__)


@app.route('/')
def index():
    return 'index'


# OSError: [Errno 98] Address already in use
# 端口被占用,是程序没有完全关闭,后台还在运行
# 在 ubuntu 中使用命令: netstat -apn  | grep 5000  找到 5000 端口对应的 pid
# 使用 kill -9 pid  命令进行清除


@app.route('/upload', methods=['POST'])
def upload():
    file = request.files.get('pic')
    file.save('aaa.png')
    return 'success'


@app.route('/data', methods=['POST'])
def data():
    data = request.data
    print(data)
    return 'ok'


if __name__ == '__main__':
    app.run(debug=True)



状态保持

  • http 是一种无状态协议,浏览器请求服务器是无状态的。
  • 无状态:指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。
  • 无状态原因:浏览器与服务器是使用 socket 套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的 socket 连接,而且服务器也会在处理页面完毕之后销毁页面对象。
  • 实现状态保持主要有两种方式:
    • 在客户端存储信息使用Cookie
    • 在服务器端存储信息使用Session

无状态协议:

  1. 协议对于事务处理没有记忆能力
  2. 对同一个 url 请求没有上下文关系
  3. 每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况
  4. 服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器
  5. 人生若只如初见

cookie
  • Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
  • Cookie基于域名安全,不同域名的Cookie是不能互相访问的
    • 浏览器的同源策略,所谓同源是指,域名,协议,端口相同。不同源的客户端脚(javascript、ActionScript)本在没明确授权的情况下,不能读写对方的资源。

make_response 获取 response 对象

set_cookie(‘username’, ‘xiaohei’, max_age=3600) 设置cookie,设置过期时间

request.cookies.get() 获取cookie

cookie 流程:

设置 cookie: 通过响应带给浏览器

获取 cookie:从请求中获取

  1. 浏览器发送登录请求,发送请求报文,带上要登录的账号和密码
  2. 服务器校验账号和密码
  3. 如果正确就给出响应,带上设置好的 cookie ,response.set_cookie('username', 'xiaohei')
  4. 浏览器会自动将 cookie 保存起来
  5. 下次请求该网站时,会把 cookie 请求带到服务器,服务器取到传过来的 cookie,根据 cookie 就可以知道是否登录,是谁登录
from flask import Flask
from flask import make_response
from flask import request

app = Flask(__name__)


@app.route('/')
def index():
    user_id = request.cookies.get('user_id')
    user_name = request.cookies.get('user_name')
    return "%s-----%s" % (user_id, user_name)


@app.route('/login')
def login():
    # 默认判断账号与密码是正确的
    response = make_response('success')
    # 设置 cookie
    response.set_cookie('user_id', '1', max_age=3600)
    response.set_cookie('user_name', 'xiaohei', max_age=3600)
    return response


@app.route('/logout')
def logout():
    response = make_response('success')
    response.delete_cookie('user_id')
    response.delete_cookie('user_name')
    return response


if __name__ == '__main__':
    app.run(debug=True)

session
  • 对于敏感、重要的信息,建议要存储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息
  • 在服务器端进行状态保持的方案就是Session
  • Session依赖于Cookie
session 流程
  1. 发送登录请求,发送请求报文,带上要登录的账号和密码
  2. 服务器处理请求:校验密码,保存用户信息到服务器,每个用户信息对应一个 sid
  3. 服务器给出相应,把 sid 返回给浏览器(cookie)
  4. 浏览器把 sid 存储起来
  5. 下次请求时默认会带上 sid, 服务器可以通过请求取到 sid,在通过 sid 取到对应的用户信息,取到信息就可以知道是否登录,是谁登录
from flask import Flask
from flask import session

app = Flask(__name__)
# 使用 session 的话,需要配置 secret_key
app.config['SECRET_KEY'] = 'asdfghj'


@app.route('/')
def index():
    user_id = session.get('user_id', '')
    user_name = session.get('user_name', '')
    return '%s -- %s' % (user_id, user_name)


@app.route('/login')
def login():
    # 假装校验成功
    session['user_id'] = "1"
    session['user_name'] = 'xiaohei'
    return 'success'


@app.route('/logout')
def logout():
    session.pop('user_id')
    session.pop('user_name')
    return 'success'


if __name__ == '__main__':
    app.run(debug=True)



上下文

上下文:相当于一个容器,保存了 Flask 程序运行过程中的一些信息。

pycharm 中移动整行代码的快捷键: shift + alt + 上下键

请求上下文
# 请求上下文中的变量
from flask import session
from flask import request

request: 封装了 HTTP 请求的内容,针对的是 http 请求

session:用来记录请求会话中的信息,针对的是用户信息。

应用上下文

它的字面意思是 应用上下文,但它不是一直存在的,它只是request context 中的一个对 app 的代理(人),所谓local proxy。它的作用主要是帮助 request 获取当前的应用,它是伴 request 而生,随 request 而灭的。

# 应用上下文中的变量
from flask import current_app
from flask import g

current_app: 应用程序上下文,用于存储应用程序中的变量。

g 变量:作为 flask 程序全局的一个临时变量,充当者中间媒介的作用,我们可以通过它传递一些数据,g 保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别

注意:不同的请求,会有不同的全局变量

from flask import Flask

# 应用上下文中的变量
from flask import current_app
from flask import g

# 请求上下文中的变量
from flask import session
from flask import request

app = Flask(__name__)


# print(request.method)
# print(session.get['user_id', ''])
# print(current_app.config.get('DEBUG'))

@app.route('/')
def index():
    # print(request.method)
    print(current_app.config.get('DEBUG'))
    return 'index'


if __name__ == '__main__':
    app.run(debug=True)



Flask-Script 扩展

通过使用Flask-Script扩展,我们可以在Flask服务器启动的时候,通过命令行的方式传入参数。而不仅仅通过app.run()方法中传参,

pip install flask-script

from flask import Flask
from flask_script import Manager


app = Flask(__name__)
# 创建 manager 与 app 进行关联
manager = Manager(app)
# 可以通过命令行在运行的时候指定运行的端口


@app.route('/')
def index():
    return 'index'


if __name__ == '__main__':
    # 需要使用 manager 去运行
    manager.run()



模板

在前面的示例中,视图函数的主要作用是生成请求的响应,这是最简单的请求。实际上,视图函数有两个作用:处理业务逻辑和返回响应内容。在大型应用中,把业务逻辑和表现内容放在一起,会增加代码的复杂度和维护成本。本节学到的模板,它的作用即是承担视图函数的另一个作用,即返回响应内容。

  • 模板其实是一个包含响应文本的文件,其中用占位符(变量)表示动态部分,告诉模板引擎其具体的值需要从使用的数据中获取
  • 使用真实值替换变量,再返回最终得到的字符串,这个过程称为“渲染”
  • Flask是使用 Jinja2 这个模板引擎来渲染模板

使用模板的好处:

  • 视图函数只负责业务逻辑和数据处理(业务逻辑方面)
  • 而模板则取到视图函数的数据结果进行展示(视图展示方面)
  • 代码结构清晰,耦合度低
jinja2
  • Jinja2:是 Python 下一个被广泛应用的模板引擎,是由Python实现的模板语言,他的设计思想来源于 Django 的模板引擎,并扩展了其语法和一系列强大的功能,其是Flask内置的模板语言。
  • 模板语言:是一种被设计来自动生成文档的简单文本格式,在模板语言中,一般都会把一些变量传给模板,替换模板的特定位置上预先定义好的占位变量名。
  • Flask提供的 render_template 函数封装了该模板引擎
  • render_template 函数的第一个参数是模板的文件名,后面的参数都是键值对,表示模板中变量对应的真实值。

使用

  • {{}} 来表示变量名,这种 {{}} 语法叫做变量代码块
  • 用 {%%} 定义的控制代码块,可以实现一些语言层次的功能,比如循环或者if语句
  • 使用 {# #} 进行注释,注释的内容不会在html中被渲染出来
from flask import Flask
from flask import render_template

app = Flask(__name__)


@app.route('/')
def index():
    return 'index'


@app.route('/demo1')
def demo1():
    my_int = 10
    my_str = "<h1>哈哈哈</h1>"
    my_list = [1, 24, 5, 62, 6]
    my_dict = {
        "id": "1",
        "name": "xiaohei"
    }
    return render_template('demo6_template.html',
                           my_int=my_int,
                           my_str=my_str,
                           my_list=my_list,
                           my_dict=my_dict,
                           )

if __name__ == '__main__':
    app.run(debug=True)

猜你喜欢

转载自blog.csdn.net/qyf__123/article/details/82988307