Flask入门

Flask入门

一、Flask 简介

1 、简介

​ Flask诞生于 2010 年,是Armin ronacher(人名)用Python语言基于Werkzeug工具箱编写的轻量 级Web开发框架,又称之为微框架。微框架中的“微”意味着 Flask 旨在保持核心,Flask本身相当于一个 内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login),都需要用第 三方的扩展来实现。比如可以用 Flask-extension加入ORM、窗体验证工具,文件上传、身份验证等。 Flask没有默认使用的数据库,你可以选择MySQL,也可以用NoSQL。其 WSGI 工具箱采用 Werkzeug(路由模块) ,模板引擎则使用 Jinja2 。 Django框架是尽可能多的提供功能给你,就象一 个暖男一样,只要你想要我就提供给你。而Flask不同,Flask设计的思想是每个人开发的web可能都不 一样,用到的技术点也都是不一样的。如果都帮web开发者设计好的话可能会束缚开发者的思想,所以 Flask只提供最核心的路由分发,你要什么功能自己集成进来,Flask给你提供最大的自由性,所以这儿也 是Flask受欢迎的原因之一。

​ Flask也算是python众多web框架中最灵活的框架。

​ Flask中文版文档: http://www.pythondoc.com/flask/

常用第三方扩展包:

Flask-SQLalchemy:操作数据库;

Flask-migrate:管理迁移数据库;

Flask-Mail:邮件;

Flask-WTF:表单;

Flask-script:插入脚本;

Flask-Login:认证用户状态;

Flask-RESTful:开发REST API的工具;

Flask-Bootstrap:集成前端Twitter Bootstrap框架;

Flask-Moment:本地化日期和时间;

Flask-Uploads: 上传文件处理

2 、 Flask 与 Django 的对比

Django

​ Django功能齐全,它提供一站式解决方案,集成了MVT(Model-View-Template)和ORM,以及后台 管理。用一个很形象的例子: Django就像一个精装修的房子,什么家具(功能)都有,直接拎包入住。

django提供了:

​ django-admin 快速创建项目工程目录 manage.py 管理项目工程 orm 模型(数据库抽象层) admin 后台管理站点 缓存机制 文件存储系统 用户认证系统

Flask

​ Flask相对于Django而言是轻量级的Web框架,Flask的两个主要核心应用是Werkzeug和模板引擎 Jinja2。 django的后台管理,表单,orm等都有现成的直接使用,而是Flask都没提供,需要使用第三方扩展 包。

​ Flask就好比待装修的房子:

二、创建项目

1 、 创建 Flask 工程

	创建Flask项目没有命令快捷方式,只需要在项目文件夹下创建一个普通的py文件,导入Flask实例化一 个Flask应用程序。 

​ 示例: 提示: 通过pycharm的运行命令 运行flask项目 通过python app.py 命令行方式运行flask项目

2 、 初始化参数

import_name: 导包的目录

static_url_path: 访问静态文件的url前缀

static_folder: 默认‘static’

template_folder: 默认‘templates’实例化Flask对象之后,静态文件默认在Flask第一个参数指定的 模块所在的目录下,静态文件使用

目录,模板使用 目录。

# 导入Flask类
from flask import Flask
# Flask 接收一个参数 name ,当前模块的文件名 
# Flask 在查找静态文件,或者模板时候默认以当前文件所在的目录去查找 
# 如果传一个不存在的模块名,将默认使用当前文件 
app = Flask(__name__) 
# 装饰器将路由映射到视图index 
@app.route('/') 
def index(): 
    return "ok" 
if __name__ == '__main__': 
    # Flask 应用程序实例的方法run启动web服务器 
    app.run(debug=True) 

在static目录下放一张图片 01.jpg,然后通过静态文件路径可以访问到:http://127.0.0.1:5000/static/ 01.jpg

3 、 配置

django项目中有一个settings.py的配置文件,但是Flask中没有,需要自己定义。

常见的两种方式:

  • 从配置文件中读取配置

    app.config.from_pyfile(‘文件名’)

  • 从类中读取配置信息

    app.config.from_object(类名)

Flask 默认是运行在线上模式,也就是说出错了是看不到错误堆栈信息的,为了好调试一般开发阶 段会将调试打开。django中默认开启调试DEBUG = True,Flask中开启调试同样只需要在配置中写 入 DEBUG=True。 从配置文件中读取配置 示例: 创建一个文件 保存配置信息

注意:配置的变量名需要用大写。如果注册多个配置文件,后面注册的同名配置会覆盖掉前面的配 置。一般使用一个工程只用一个配置文件。

#导入Flask类 from flask import Flask 
# Flask 接收一个参数 name , 
# 导入模块的目录, flask以这个目录为基础,寻找静态文件目录static和模板目录templates 
app = Flask(__name__, 
            # static_url_path='/python', 
            # 访问静态资源的url前缀,默认是/static 
            static_folder='static', 
            # 静态文件目录名,默认static 
            template_folder='templates', # 模板文件目录名,默认templates 
           ) 
# 装饰器将路由映射到视图index 
@app.route('/') 
# 定义一个视图 
def index(): 
    return 'hello' 
# 设置配置信息获取方式,从配置文件中查找 
# app.config.from_pyfile('config.cfg') 

class Config(object): 
    DEBUG = False 
    
# 设置配置信息获取方式,从配置对象中查找 
app.config.from_object(Config) 
if __name__ == '__main__': 
    # Flask 应用程序实例的方法run启动web服务器 
    app.run() 

4 、读取配置参数

第一种方式:

在能访问到app对象的文件中可直接使用app.config.get方式获取配置参数 app.config.get(‘配置’)

第二种方式:

需要从flask中导入current_app,在整个Flask项目中都可以使用,实际上也是app对象 相到于一个别名。 current_app.config.get(‘配置名’)

# 导入Flask类 
from flask import Flask,current_app 
# Flask 接收一个参数 name , 
# 导入模块的目录, flask以这个目录为基础,寻找静态文件目录static和模板目录templates 
app = Flask(__name__, 
            # static_url_path='/python', 
            # 访问静态资源的url前缀,默认是/static 
            static_folder='static', # 静态文件目录名,默认static 
            template_folder='templates', # 模板文件目录名,默认templates 
           ) 
# 装饰器将路由映射到视图index 
@app.route('/') 
# 定义一个视图 
def index(): 
    #a = current_app.config.get('A') 
    a = app.config.get('A') 
    b = app.config.get('B') 
    return str(a + b) 
# 设置配置信息获取方式,从配置文件中查找 
# app.config.from_pyfile('config.cfg') 

class Config(object): 
    DEBUG = False 
    A = 2 
    B = 5 
    
    
# 设置配置信息获取方式,从配置对象中查找 
app.config.from_object(Config) 

if __name__ == '__main__': 
    # Flask 应用程序实例的方法run启动web服务器 
    app.run() 

5 、app.run参数

run方法源码
from werkzeug.serving import run_simple 
def run( self, 
        host: t.Optional[str] = None, 
        port: t.Optional[int] = None, 
        debug: t.Optional[bool] = None, 
        load_dotenv: bool = True, 
        **options: t.Any, 
       ) -> None: 
    if debug is not None: 
        self.debug = bool(debug) 
        
        server_name = self.config.get("SERVER_NAME") 
        sn_host = sn_port = None 
        
        if server_name: 
            sn_host, _, sn_port = server_name.partition(":") 
            
        if not host: 
            if sn_host: 
                host = sn_host 
            else: 
                host = "127.0.0.1" 
                
        if port or port == 0: 
            port = int(port) 
        elif sn_port: 
            port = int(sn_port) 
        else: 
            port = 5000 
            
    from werkzeug.serving import run_simple 
		try: 
            run_simple(t.cast(str, host), port, self, **options) 
        finally: 
            self._got_first_request = False 

从源码中可以看出run方法是启动一个werkzug工具箱提供的简易服务器。

参数:

host 服务器主机地址,默认使用本机地址’127.0.0.1’ ,假如设置’0.0.0.0’,则可以监听本机所有ip地址 port 端口号,默认 5000

debug 调试,参数是bool值 ,表示是否开启调试,True开启调试。默认Flase

三、路由配置

路由就是根据请求的 url 找到对应处理的函数视图的过程。在请求之前应该建立好一张路由表保存url 与视图的对应关系,这样有请求过来才能正确找到对应的视图。

Flask中有两种常用方式构建路由规则:

1 、@app.route(‘url规则’) decorator装饰器方式

2 、app.add_url_rule()

add_url_rule(self, rule, endpoint=None, view_func=None, **options)参数的含义如下:

rule: url 规则字符串,可以是静态的 /path,也可以包含 / endpoint:要注册规则的 endpoint,默认是 view_func 的名字 view_func:对应 url 的处理函数,也被称为视图函数

# 装饰器将路由映射到视图index 
@app.route('/') 
# 定义一个视图 
def index(): 
    return 'ok' 
#这两种方法是等价的 
#app.add_url_rule('/', 'index', index) 
1 、查看路由信息

在django中url统一配置在URLconf配置文件中,但是Flask直接配置在视图没有统一的配置文件如何查 看路由信息呢?
app.url_map查看所有路由

示例:

#导入Flask类 
from flask import Flask 
app = Flask(__name__) 
# 定义一个视图 
# @app.route('/') 
def index(): 
    print(app.url_map) 
    return 'hello' 
# @app.route('/detail') 
def detail(): 
    return 'detial' 
# @app.route('/list') 
def list(): 
    return 'list' 
app.add_url_rule('/', endpoint='index', view_func=index) 
app.add_url_rule('/detail', endpoint='detail', view_func=detail) app.add_url_rule('/list', endpoint='list', view_func=list) 
if __name__ == '__main__': 
    # Flask 应用程序实例的方法run启动web服务器 
    app.run(debug=True)

执行视图会打印出下面url信息:

每一条 Rule对应信息:

  • url规则
  • 支持的请求方式,默认支持get请求,不支持post.
  • 对应的视图
Map(([<Rule '/' (OPTIONS, HEAD, GET) -> index>,
<Rule '/static/<filename>' (OPTIONS, HEAD, GET) -> static>])

可以在python shell中导入flask项目查看:

In [5]: from app import app 
In [6]: app.url_map 
Out[6]: 
Map(([<Rule '/' (OPTIONS, HEAD, GET) -> index>,
<Rule '/static/<filename>' (OPTIONS, HEAD, GET) -> static>])
2 、同一路由装饰不同视图

同一个路由规则装饰不同函数,只有第一个视图函数会匹配到。虽然都生成了路由表,但是url匹配中第 一个规则之后就会调用视图,不再继续往下匹配。

# 同一个url规则装饰不同的视图函数 
@app.route('/index') 
def index1(): 
    return 'index1' 
@app.route('/index') 
def index2(): 
    return 'index2' 
3 、一个视图函数多个路由装饰器

同一个视图函数有多个路由装饰器,会生成多条路由信息,每条对应规则的url都可以访问到视图函 数。

4 、methods 参数

HTTP (与 Web 应用会话的协议)有许多不同的访问 URL 方法。默认情况下,路由只回应 GET 请 求,但是通过route() 装饰器传递 methods 参数可以改变这个行为

methods 参数接收一个字典,元素为字符串形式的请求方式名称。 如果不传methods参数,默认支 持 GET, HEAD,OPTIONS

OPTIONS 给客户端提供一个敏捷的途径来弄清这个 URL 支持哪些 HTTP 方法。 从 Flask 0.6 开始,实 现了自动处理。

HEAD 浏览器告诉服务器:欲获取信息,但是只关心 消息头 。应用应像处理 GET 请求一样来处理 它,但是不分发实际内容。在 Flask 中你完全无需 人工 干预,底层的 Werkzeug 库已经替你打点好 了。

定义一个视图 
@app.route('/login', methods=['GET', 'POST']) 
def login(): 
    print(app.url_map) 
    if request.method == 'GET': 
        return 'get' 
    elif request.method == 'POST': 
        return 'post'    
5 、反向解析

url_for() 函数 可以通过视图函数名称,反向解析得到视图对应的url

url_for函数:

from flask import Flask, url_for 
app = Flask(__name__) 
@app.route("/index/python") 
def req_python(): 
    return 'python' 
@app.route("/url_for") 
def req_url(): 
    """url_for 反向解析""" 
    return '[链接](%s)' % url_for("req_python") 
if __name__ == '__main__': 
    app.run(debug=True)
6 、动态路由

要给 URL 添加变量部分,把这些特殊的字段标记为 , 这个部分将会作为命名参数 传递到视图函数中。

变量放在<> 中

from flask import Flask
app = Flask(__name__)
@app.route('/param/<name>')
def get_url_param(name):
	return '参数是:%s' % name
if __name__ == '__main__':
	app.run(debug=True)

规则可以用 converter:variable_name 指定一个可选的转换器。

转换器: 默认匹配的是不带/的字符串

int: 接受整数

float:接受浮点数

path: 和默认的相似,但也接受斜线

# 默认<>的规则匹配不带/的整数
@app.route('/param_int /<int:id>')
def get_url_param_int(id):
	return '获取的参数是: %s '% id
# 默认<>的规则匹配不带/的 浮点数
@app.route('/param_float/<float:f>')
def get_url_param_float(f):
	return '获取的参数是: %s '% f
# 匹配参数后面带/
@app.route('/param_path/<path:p>')
def get_url_param_path(p):
	return '获取的参数是: %s '% p

7 、自定义正则转换器

Flask路由转换器,没有提供基于正则的,但是我们可以自定义基于正则的路由转换器。

  • 自定义转换器必须继承BaseConverter类,自定义转换器需要重写父类的__init__方法

  • 注册转换器,url_map中保存了所有的路由转换器,是字典类型

from werkzeug.routing import BaseConverter
from flask import Flask, url_for
app = Flask(__name__)
# 正则转换器
class RegexConverter(BaseConverter):
    def __init__(self, url_map, *args):
        # 调用父类的初始化方法
        super(RegexConverter, self).__init__(url_map)
        # 将正则表达式传给转换器对象,flask在解析路径的时候,会来这里获取regex保存的正则表达
        式
        self.regex = args[0]
    def to_python(self, value):
        # 对获取到的参数进行处理
        # 默认获取到是字符串,可以对获取到的参数进行处理,比如类型转换
        # 这样就可以在视图中直接使用
        print(type(value))
        print(value)
        return value
    def to_url(self, value):
        # 当使用反解析的时候会调用这个方法,可以对参数进行处理
        print(value)
        return value
# 注册re 转换器 RegexConverter
app.url_map.converters['re'] = RegexConverter
@app.route("/param_re/<re('\d'):num>/<re('\d+'):num2>")
def get_param_re(num, num2):
    """url中提取参数"""
    return '自定义正则转换器获取参数1:%s , 参数2:%s' % (num, num2)
@app.route('/get_param_re_url/')
def get_param_url():
"""在视图函数中获取url"""
    return '<a href="%s">to_url演示</a>' % (url_for('get_param_re', num='1',num2='2'))

四、处理请求

1 、 request 对象

Flask中获取请求数据,与django中不同,django视图中第一个参数必须是HttpRequest对象,Flask 中需要导入从flask中导入request对象,request对象中已经封装当前所有的请求参数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IUpZaemS-1634869750942)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211019171757374.png)]

与路径相关的属性

path、script_root、url、base_url、url_root

比如用户访问这个链接: http://www.example.com/myapplication/page.html?x=y

这个情况下,上面提到的属性的值会为如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kHuUDunr-1634869750946)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211019171851332.png)]

from flask import Flask, request
app = Flask(__name__)
@app.route('/python/index')
def index():
    print(request.path)
    print(request.script_root)
    print(request.base_url)
    print(request.url)
    print(request.url_root)
    return '请求参数测试'
if __name__ == '__main__':
    app.run(debug=True)
2 、 Postman 插件使用

Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。无论是web前端开发 或 android、ios开发,只要涉及调用后端接口,postman这类型工具就必不可少了 利用这个插件模拟浏览器以不同的请求方式向服务器提交参数

2.1 下载及加载Postman
  • 使用chrome商店在线下载postman

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7TXpHdq3-1634869750949)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211019172101683.png)]

离线下载postman插件,可以自己到网上下载

  • 解压文件,在解压后的文件夹中找到.crx文件,将.crx改为.zip或.rar,并且解压

  • 把_metadata 文件夹 改为metadata

  • 文件夹 加载Postman

  • 启动Postman

    进入 chrome://apps/

2.2 使用Postman

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sLcAwugE-1634869750953)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211019172427993.png)]

from flask import Flask, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
    # form 获取post提交的数据
    post_dict = request.form
    print("表单数据: ", post_dict)
    # args 获取查询字符串,即url ? 后面的参数
    query_dict = request.args
    print("查询字符串: ", query_dict)
    # 获取所有查询参数,跟post参数
    all_dict = request.values
    print("所有参数: ", all_dict)
    # 获取cookie
    cookie = request.cookies
    print(cookie)
    # 获取某个参数值get方法,如果不存在这个key会报错,为了不报错可以传一个默认值,如果不存在
    key,将使用默认值。
    # 如果是多值使用getlist方法,如果不存在,则返回空列表。
    a = query_dict.get('a', '')
    b = query_dict.getlist('b')
    print("参数a: ", a)
    print("参数b: ", b)
    return 'ok'
if __name__ == '__main__':
    app.run(debug=True
3 、文件上传

已上传的文件存储在内存或是文件系统中一个临时的位置。你可以通过请求对象的 files 属性访问它 们。每个上传的文件都会存储在这个字典里。它表现近乎为一个标准的 Python file 对象,但它还有一 个 save() 方法,这个方法允许你把文件保存到服务器的文件系统上。

前端Postman:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rp36Brvf-1634869750955)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211019172622582.png)]

后端Flask:

from flask import Flask, request
app = Flask(__name__)
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # 查看文件上传列表
        # print(request.files)
        f = request.files['myfile']
        f.save('uploaded_file.txt')
        return "文件上传成功..."
    else:
        return "您的请求方式不正确..."
if __name__ == '__main__':
app.run(debug=True)

如果你想知道上传前文件在客户端的文件名是什么,你可以访问 filename 属性。。如果你要把文件按 客户端提供的文件名存储在服务器上,那么请把它传递给 Werkzeug提供的 secure_filename() 函数: 传递一个文件名,它会返回一个安全的文件名,防止上传的文件名不符合服务器文件命名要求。

示例:

from flask import request
from werkzeug.utils import secure_filename
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    # 判断是Post请求方式
    if request.method == 'POST':
        f = request.files['myfile']
        f.save('./uploads/' + secure_filename(f.filename))
        return "文件上传成功..."
    else:
        return "您的请求方式不正确..."

注意:secure_filename 不能识别中文。 secure_filename仅返回ASCII字符。所以, 非ASCII(比如汉 字)会被过滤掉,空格会被替换为下划线。你也可以自己处理文件名自动生成一个随机文件名,或是在 使用这个函数前将中文替换为拼音或是英文。2435357ab563475afdc.jpg

使用md5值作为文件名****

from flask import Flask, request
from werkzeug.utils import secure_filename
from hashlib import md5
app = Flask(__name__)
@app.route('/uploads', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # 查看文件上传列表
        # print("上传的文件列表: ",request.files)
        f = request.files['myfile']
        # 查看上传的文件名
        print("上传的文件名: ", f.filename)
        # 1.直接使用上传的文件名
        # f.save('./uploads/' + f.filename)
        # 2.使用secure_filename()处理过的文件名
        # f.save('./uploads/' + secure_filename(f.filename))
        # 3.使用md5值作为文件名 a图片.png--->bytes(编码成二进制串)
        md5_filename = md5(f.filename.encode('utf-8')).hexdigest()
        # 从右侧开始查找圆点的索引值
        dot_index = f.filename.rindex('.')
        # 获取上传文件的后缀.png
        file_suffix = f.filename[dot_index:]
        new_file_name = md5_filename + file_suffix
        print("新的文件名:", new_file_name)
        f.save(f'./uploads/{new_file_name}')
        return "文件上传成功..."
    else:
        return "您的请求方式不正确..."
if __name__ == '__main__':
    app.run(debug=True)

五、 处理响应

1、响应数据
1) 关于响应

视图函数的 return 值会自动转换为一个响应对象。如果返回值是一个字符串, 它被转换为该字符串为 主体的、状态码为 200 的 ,MIME 类型是 text/html 的响应对象。 Flask 把返回值转换为响应对象的逻辑:

如果返回的是一个字符串,响应对象会用字符串数据和默认参数创建。

如果返回的是一个元组,且元组中的元素可以提供额外的信息。 这样的元组必须是 (response, status, headers) 形式且至少含有一个元素。 status 值将会覆盖状态代码,headers 可以是一 个列表或额外的消息头值字典 。

如果返回的是一个合法的响应对象,它会从视图直接返回。

我们之前都是直接返回字符串,现在测试一下 返回元组:

from flask import Flask
app = Flask(__name__)
@app.route('/index')
def index():
    # 1.直接返回字符串,则flask会默认构建一个响应对象返回
    # return "人生苦短,我用python"
    """
    2.返回元组 :(response,status,headers)
    参数介绍: 一个参数是响应体,第二个参数是响应状态码,第三个参数响应头 可以是一个字典
    flask会按照参数的设置返回相应的响应对象
    """
    return ("人生苦短,我用p", '206 very good', {'Server': 'zzt_Server1.0','subject': 'Flask'})
if __name__ == '__main__':
app.run(debug=True)

2) 响应对象

使用make_response 创建响应对象

from flask import Flask, make_response
app = Flask(__name__)
@app.route('/index')
def index():
    # 使用make_response()函数构建Response响应对象
        # response = make_response('Flask框架讲解', '404 File Not Found', {'subject':'python'})
    response = make_response()
    # 自定义响应体
    response.data = "flask框架"
    # # 自定义状态码
    response.status = '206 ok'
    # # 自定义请求头
    response.headers['subject'] = 'Flask'
    # 返回响应对象
    return response
if __name__ == '__main__':
    app.run(debug=True)	

3) 返回 模板页面

使用 render_template 方法渲染模板并返回

前端模板

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
我的模板html内容
<br/>{{ 变量1 }}
<br/>{{ 变量2 }}
</body>
</html>

后端视图

from flask import Flask, render_template, make_response
import re

app = Flask(__name__)

@app.route('/index')
def index():
    product = "iphone13"
    price = 5999
    # 【方式一】
    # # 使用make_response()函数构建Response响应对象
    # response = make_response()
    # # 自定义响应体
    # data = open('./templates/demo.html', 'r', encoding='utf-8').read()
    # data = re.sub('{{ product }}', product, data)
    # data = re.sub('{{ price }}', str(price), data)
    # response.data = data
    # # 返回响应对象
    # return response
    # 【方式二】 使用render_template函数
    return render_template('demo.html', product=product, price=price)
if __name__ == '__main__':
    app.run(debug=True)

在前面内容中我们都是返回字符串,但是很多web开发中都是要求前后端分离的,前端一般会要求后 端返回json数据。

在django的学习中我们知道返回json数据有一个JsonResponse对象,接收一个python字典作为参 数。Flask中也有一个类似的对象可以返回json数据。 jsonify: 返回json格式的数据

from flask import Flask, make_response, jsonify
import json
app = Flask(__name__)
@app.route('/index')
def request_json():
    data = {
    'a': 1,
    'b': 2
    }
    # 普通方式返回json数据
    # 将字典对象转为json字符串
    # resp_json = json.dumps(data)
    # 创建一个响应对象
    # response = make_response(resp_json)
    # 添加响应头,表示返回的是json数据
    # response.headers["Content-Type"] = "application/json"
    # return response
    # 将字典转换成json对象后返回
    return jsonify(data)
if __name__ == '__main__':
    app.run(debug=True)
2、异常处理
1) abort 函数

abort函数的作用是:放弃请求并返回错误代码

相当于python中的raise 抛出异常

详细HTTP状态码 :https://tool.oschina.net/commons?type=5

# 导入Flask类
from flask import Flask, abort
app = Flask(__name__)
@app.route('/')
def index():
    # 终止视图执行,并返回HTTP状态码
    abort(500)
    return 'ok'
if __name__ == '__main__':
    app.run(debug=True)

2 )自定义错误处理视图

使用 errorhandler 装饰器,接受一个http状态码为参数。

自定义的错误视图不单单作用于abort函数抛出的错误,也作用于整个Flask应用对应错误码。 自定义错误处理视图接收一个参数,是Flask应用的默认报错信息

# 导入Flask类
from flask import Flask, abort
app = Flask(__name__)
@app.route('/')
def index():
    # 终止视图执行,并返回HTTP状态码
    abort(500)
    return 'ok'
    # 自定义错误处理视图函数
    # 使用 errorhandler 装饰器,接受一个http状态码为参数。
    # 自定义的错误视图不单单作用于abort函数抛出的错误,也作用于整个Flask应用对应错误码。
    # 自定义错误处理视图接收一个参数,是Flask应用的默认报错信息
@app.errorhandler(403)
def error(e):
    return f'禁止访问,可能权限不够,具体错误信息: <br/>{e}'
if name == '__main__':
    app.run(debug=True)
3、重定向
redirect 函数

Flask中的重定向使用 redirect 函数,接收一个url为参数

案例:

from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route('/index')
def index():
    """index视图"""
    return '我是首页'
@app.route('/login')
def login():
    # 重定向到 index 视图,使用url_for反解析获得url
    return redirect(url_for('index'))
if __name__ == '__main__':
    app.run(debug=True)

六、Cookie与Session

1、Cookie
1) Cookie 简介

response对象的 set_cookie 方法来设置 Cookies。 request对象的 cookies 属性是客户端提交过来的 所有cookie键值对,字典类型。

2) 设置 cookie

cookie 是以键值对的形式保存在浏览器中。

设置cookie我们比较关心的三个参数:

key cookie的键

value cookie的值

max_age=None 超时时间,单位是秒

expires=None 超时时间,datatime对象

import datetime
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/set_cookie')
def set_cookie():
    """设置cookie"""
    resp = make_response('设置cookie')
    # 向浏览其中写入一个key为a,值为python,超时时间在2021,10,19日
    # resp.set_cookie('a', 'python', expires=datetime.datetime(year=2021,month=10, day=19))
    # 向浏览其中写入一个key为a,值为python,超时时间是60*60秒之后
    resp.set_cookie('a', 'python', max_age=60*60)
    return resp
if __name__ == '__main__':
app.run(debug=True)
3) 获取 cookie

request 对象中的cookie属性是包含了所有浏览器上传到服务器的cookie。 get 方法获取其中的键 值,可以传一个默认值。

@app.route('/get_cookie')
def get_cookie():
    """获取cookie"""
    # 通过键获取cookie值,如果没有这个键返回None
    a = request.cookies.get('a')
    print(a)
    # 可以传一个默认值,如果不存在这个键,将使用默认值。
    b = request.cookies.get('b', 'not found')
    print(b)
    return f'获取到的cookie是: a:{a} b:{b}'

4) 、 删除 cookie
@app.route('/del_cookie')
def del_cookie():
    """删除cookie"""
    response = make_response('删除cookie')
    # 将key为a的cookie 删除
    response.delete_cookie('a')
    return response
2、Session
1) Session简介

在学习django中的所有的session是保存在服务器中的数据库的。将sessionid写到浏览器,浏览器发 送请求的时候 将sessionid传回给服务器,然后再利用sessionid到数据库中匹配对应用户的session信 息。django中创建好项目就有默认的数据库,这个保存在数据库中好理解。

但是在Flask中,我们并没有数据库配置,那么session信息保存在哪个位置呢。实际上Flask的session 是基于cookie加secret_key 进行加密后保存在cookie中的。

session具体的使用方法:

首先设置SECRET_KEY:

# Flask中需要使用session必须先配置SECRET_KEY 或者 自己输入一个字符串
app.config['SECRET_KEY'] = os.urandom(24)
app.config['SECRET_KEY'] = 'sdfsdfs&&^%dsdf*/*$#'
----------
import os
os.urandom(n)
返回n个字节的适合加密的随机字节串
视图函数中使用session跟python字典类似使用key获取值,或者使用get方法。

案例

import os
from flask import Flask, session

app = Flask(__name__)
# app.config['SECRET_KEY'] = 'sdfsdfs&&^%dsdf*/*$#'
app.config['SECRET_KEY'] = os.urandom(24)

@app.route('/set_session')
def set_session():
    # 设置session 字典形式
    session['name'] = 'python'
    session['password'] = '123456'
    return 'session'

@app.route('/get_session')
def get_session():
    # 获取session 采用[key]方式取值,如果key不存在会报错。
    name = session['name']
    print(name)
    # 获取session 采用get方式取值,如果key不存在返回None,
    pwd = session.get('password')
    print(pwd)
    return 'name:%s ' % name

if __name__ == '__main__':
app.run(debug=True)
2 ) 删除session

可以直接使用session.pop(‘key’,None):

session.pop(‘name’,None)

如果要删除session中所有数据使用:

clear(): session.clear()

@app.route('/del_session')
def del_session():
    # 删除session的某个键值对,返回删除的session值on,如果不存在可以设置一个默认值。
    result = session.pop('name', None)
    # 清除整个session.
    session.clear()
    return '删除session %s ' % result
3) 设置session超时时间

Flask的默认session利用了Werkzeug的SecureCookie,把信息做序列化(pickle)后编码(base64),放 到cookie里了。

过期时间是通过cookie的过期时间实现的。

过期时间是这样来设置:

from datetime import timedelta
from os import urandom
from flask import Flask, session, redirect, url_for, escape, request

app = Flask(__name__)
app.secret_key = urandom(24)

@app.route('/')
def index():
    if 'username' in session:
    return '内部系统首页: Logged in as %s' % escape(session['username'])
    return 'You are not logged in'

@app.route('/login', methods=['GET', 'POST'])
def login():
    # 设置session的持久性为True
    session.permanent = True
    # 设置session的有效时间 :两分钟后失效
    app.permanent_session_lifetime = timedelta(minutes=2)
    if request.method == 'POST':
    session['username'] = request.form['username']
    return redirect(url_for('index'))
    return '''
    <form method="post">
    <p><input type=text name=username>
    <p><input type=submit value=Login>
    </form>
    '''

@app.route('/logout')
def logout():
    # remove the username from the session if it's there
    session.pop('username', None)
    return redirect(url_for('index'))

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

七、请求钩子与上下文

1、请求钩子

在每个请求执行视图之前或者执行完成之后,需要做一些操作,为了避免每个视图都重写重复代码, Flask提供了四个通用函数完成一系列操作,即请求钩子。

请求钩子使用修饰器实现。Flask常用的钩子函数:

before_first_request:注册一个在处理第一个请求之前运行的函数。 before_request:注册一个在处理请求之前运行的函数。

after_request:注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行,接收一个响应对 象为参数,需要返回一个响应对象

teardown_request:注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行,接收一个响 应对象为参数,需要返回一个响应对象。

import time
from flask import Flask, Response

app = Flask(__name__)

# 只有在第一次请求的时候执行
@app.before_first_request
def first_request():
    print("before_first_request 执行")
    
# 每次请求之前执行
@app.before_request
def before_request_():
    print('before_request执行') # 每次执行完成后没有未处理的异常抛出才会执行

# 每次请求执行完后执行,需要传一个Response参数,且返回一个修改后的Response对象
@app.after_request
def after_request(response: Response):
    print('after_request 执行')
    # 添加响应头
    response.headers["Content-Type"] = "application/json"
    return response

# 每次请求完最后执行,需要传一个异常参数
@app.teardown_request
def teardown_request_(e):
    print('teardown_request 执行...')
    print("teardown_request", e)
    return e

@app.route('/contacts')
def query_contacts():
    print('查询本单位联系人')
    # a = 1 / 0
    # raise Exception("文件异常...")
    return '本单位人员通讯录...'

@app.route('/login')
def login():
    return "登录页面..."

if __name__ == '__main__':
    # Flask 应用程序实例的方法run启动web服务器
    app.run() # 出现异常时,只有debug=False 才会调用@app.teardown_request函数
2、Flask 上下文
1) 应用上下文

Flask 中有两个应用上下文对象:

current_app 对象

g 对象

2) current_app 对象

current_app 对象,它被绑定到当前请求的应用的引用。

如果在程序中需要访问应用,那么需要将应用显式地到处传递应用,如果使用current_app对象,我们 不需要关心创建的应用,当我们访问current_app对象的时候,实际上是访问请求的应用。

# 导入Flask类
from flask import Flask, current_app

# 在创建app应用的时候,每个创建的对象名可能都不一样。
# 使用current_app 应用上下文,我们可以不用关心应用怎么创建的。
# app = Flask( name )
# app_2 = Flask( name )
my_app = Flask(__name__)

class Config(object):
    USERNAME = 'hongfei'
    PASSWORD = '123456'
    my_app.config.from_object(Config)
    
@my_app.route('/')
def index():
    username = my_app.config.get("USERNAME") # 可以不通过Flask实例名称获取配置
    password = current_app.config.get("PASSWORD") # 获取配置
    return f'username={username},password={password}'
if __name__ == '__main__':
    # Flask 应用程序实例的方法run启动web服务器
    my_app.run(debug=True)
3) g 对象

g对象是应用上下文的一种,每一个请求过来都会创建一个g对象。g对象就是一个作用于app应用的全 局变量。每个请求进来g对象都先置为空。

在钩子函数与视图函数中变量的传递,可以用g对象做为全局变量去传递。

from flask import Flask, g

# 每次请求之前执行
app = Flask(__name__)

@app.before_request
def before_request_():
    g.s = 'g对象传过来的参数'
    print('before_request执行')

@app.route('/')
def index():
    print('index 执行')
    # 在视图函数中通过g对象获取参数
    print(g.get('s'))
    return 'ok'

@app.teardown_request
def teardown_r(e):
    print("teardown_r", g.get('s'))
    return e

if __name__ == '__main__':
    app.run()
4) 请求上下文

请求上下文保存了客户端和服务器交互的数据

Flask 中请求上下文有两个对象:

request 对象

关心应用怎么创建的。
# app = Flask( name )
# app_2 = Flask( name )

my_app = Flask(name)

class Config(object):
USERNAME = ‘hongfei’
PASSWORD = ‘123456’
my_app.config.from_object(Config)

@my_app.route(’/’)
def index():
username = my_app.config.get(“USERNAME”) # 可以不通过Flask实例名称获取配置
password = current_app.config.get(“PASSWORD”) # 获取配置
return f’username={username},password={password}’
if name == ‘main’:
# Flask 应用程序实例的方法run启动web服务器
my_app.run(debug=True)


##### 3) g 对象 

g对象是应用上下文的一种,每一个请求过来都会创建一个g对象。g对象就是一个作用于app应用的全 局变量。每个请求进来g对象都先置为空。

 在钩子函数与视图函数中变量的传递,可以用g对象做为全局变量去传递。

```python
from flask import Flask, g

# 每次请求之前执行
app = Flask(__name__)

@app.before_request
def before_request_():
    g.s = 'g对象传过来的参数'
    print('before_request执行')

@app.route('/')
def index():
    print('index 执行')
    # 在视图函数中通过g对象获取参数
    print(g.get('s'))
    return 'ok'

@app.teardown_request
def teardown_r(e):
    print("teardown_r", g.get('s'))
    return e

if __name__ == '__main__':
    app.run()
4) 请求上下文

请求上下文保存了客户端和服务器交互的数据

Flask 中请求上下文有两个对象:

request 对象

session 对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值