温馨提示:这篇文章已超过395天没有更新,请注意相关的内容是否还可用!
摘要:本指南介绍了Python中小而精的Web开发框架Flask,包括其特点、安装和使用方法。本指南详细阐述了Flask的核心概念,如路由、视图函数、模板等,并提供了丰富的示例代码。通过学习本指南,读者可以熟练掌握Flask框架的使用,并能够快速开发出功能强大、性能稳定的Web应用程序。
文章目录
- Flask 简介说明
- Flask 核心依赖
- Flask 常用扩展
- Flask 快速启动
- 工作流程
- 代码示例
- Flask 快速启动控制台
- Flask 快速启动效果
- Flask 启动参数
- Flask 路由定义
- Flask 支持的 HTTP 请求方式:
- 路由装饰器中的参数
- Flask 路由参数
- Flask 路由蓝图
- 路由蓝图的优点
- 路由蓝图的参数
- Flask 请求对象
- Flask 响应对象
- Flask 会话保持
- Cookie 简介
- Cookie使用示例代码
- Session 简介
- Session使用示例代码
- Flask 异常处理
- abort函数(主动抛出)
- errorhandler 装饰器
- Flask 钩子函数
- 常用钩子函数
- 示例代码
- 示例代码说明
- 钩子函数工作流程
- Flask 模板语言
- Flask 模版渲染
- 概念
- 示例代码
- Flask Web表单
- Web表单创建流程
- WTForms支持字段
- WTForms常用验证函数
- Web表单示例代码
- Flask 跨域资源共享
- 1. 安装 Flask-CORS
- 2. 导入并使用 Flask-CORS
- 3. 自定义 CORS 配置
- Flask 数据库操作
Flask 简介说明
Flask 是一个用 Python 编写的轻量级 Web 应用框架。
它的核心非常简单,但是可以通过各种插件来扩展,使其可以用来构建复杂的 Web 应用。
Flask 的设计目标是保持核心简单且易于使用,同时能够被扩展以适应不同的应用需求。
Flask框架主要特点:
- 轻量级:Flask 本身只提供了最基础的 Web 功能,如URL路由、请求和响应处理等。这使得 Flask 非常轻量,易于学习和使用。
- 易于扩展:虽然 Flask 本身功能有限,但是它可以通过各种插件来扩展,如数据库操作(Flask-SQLAlchemy)、表单处理(Flask-WTF)、用户认证(Flask-Login)等。
- 模板引擎:Flask 使用 Jinja2 作为其模板引擎,可以方便地生成动态 HTML 内容。
Flask 核心依赖
Flask框架的核心依赖是Werkzeug和Jinja2。
Werkzeug是一个遵循WSGI协议的Python函数库,提供了许多用于构建Web应用程序的工具,包括路由、调试、表单处理、会话管理、文件上传、JSON处理、安全性等。
Jinja2是一个Python的模板引擎,常与Flask一起使用来渲染HTML页面,它允许在HTML文件中使用变量和逻辑控制结构来动态生成内容。
Flask本身相当于一个内核,其他的功能都通过扩展来实现,如邮件扩展Flask-Mail、用户认证Flask-Login、数据库Flask-SQLAlchemy等。
Flask 常用扩展
这种设计理念使得Flask保持了其核心的简单性,同时鼓励开发者根据项目的具体需求,通过集成各种第三方扩展来丰富和扩展其功能。
这种灵活性使得Flask能够应对各种复杂的Web开发场景,同时保持代码的清晰和可维护性。
Flask的插件库是其强大功能的重要来源,允许你根据自己的需求,选择适合的插件来扩展Flask的功能,从而实现网站的个性化定制。
例如,对于数据库操作,Flask-SQLAlchemy插件提供了对SQLAlchemy的集成,使得数据库操作变得更加简单和直观;对于邮件处理,Flask-Mail插件则提供了对SMTP服务器的支持,使得发送邮件变得轻而易举。
用途 插件名称 安装方法 数据库操作 Flask-SQLAlchemy pip install flask-sqlalchemy 数据库迁移 Flask-Migrate pip install flask-migrate 表单处理 Flask-WTF pip install flask-wtf 邮件处理 Flask-Mail pip install flask-mail 后台管理 Flask-Admin pip install flask-admin 用户认证 Flask-Login pip install flask-login Token认证 Flask-JWT-Extended pip install flask-jwt-extended 接口频率限制 Flask-Limiter pip install flask-limiter Session管理 Flask-Session pip install flask-session 密码生成 Flask-Bcypt pip install flask-bcypt 缓存 FLask-Caching pip intall flask-caching 页面调试 Flask-DebugToobar pip install flask-debugtoolbar 静态文静缓存 Flask-Static-Digest pip install flask-static-digest 本地化日期时间 Flask-Moment pip install flask-moment 集成BootStrap框架 Flask-Bootstrp pip install flask-bootstrap 开发REST风格根据 Flask-RESTful pip install flask-restful Flask 快速启动
工作流程
Flask 请求-响应工作流程
代码示例
# 导入类flask.Flask from flask import Flask # 实例化创建一个Flask应用,app为应用的名称,__name__是一个标识Python模块的名字的变量 # 若当前模块是主模块,那么此模块的名字就是__main__ # 若当前模块是被import的,则此模块名字为文件名 app = Flask(__name__) # app.route('/')返回一个装饰器,为函数index()绑定对应的URL,当用户访问这个URL时就会触发这个函数 @app.route("/") def hello(): # 响应:返回给浏览器的数据 return "Hello Flask" # 再添加一个路由和视图函数 @app.route("/index") def index(): return "Index Test 首页测试..." if __name__ == '__main__': # run() 启动的时候可以添加参数 # debug 是开启调试牧师,开启后修改过python代码会自动重启服务 # port 启动指定服务器的端口号,默认5000 # host 启动指定主机IP地址,默认是128.0.0.1,指定为0.0.0.0代表本机所有IP app.run(debug=True)
Flask 快速启动控制台
Flask 快速启动效果
访问网址"http://127.0.0.1:5000/"
Flask 启动参数
在 Flask 中,**app.run()**方法用于启动服务器;
它有几个参数,可以用来配置服务器的行为。
下面是 app.run()方法的参数及其含义:
- **host:**指定服务器监听的主机地址,默认值:'127.0.0.1'也就是只在本机上可访问
- **port:**指定服务器监听的端口号,默认值: 5000。
- **debug:**如果设置为 True,服务器将运行在调试模式下。在调试模式下,服务器会在发生错误时显示详细的错误页面,而不是简单的错误消息。这对于开发和调试非常有用,但在生产环境中应该禁用调试模式。
- **load_dotenv:**如果设置为 True,Flask 将在启动时加载 .env 文件中的环境变量。这通常用于存储敏感信息,如数据库密码或 API 密钥。
- **threaded:**如果设置为 True,服务器将使用多线程来处理请求。这可以提高并发性能,但可能会增加资源消耗。
- **processes:**指定服务器应该使用多少个进程来处理请求。通常,这个参数只在多线程模式下有效。增加进程数可以提高并发性能,但也会增加资源消耗。
- **passthrough_errors:**如果设置为 True,服务器将不会捕获异常,而是将它们直接传递给 WSGI 应用程序。这通常用于在应用程序中自定义错误处理。
Flask 路由定义
在Flask中,@app.route() 装饰器发挥着至关重要的作用;
它负责定义和映射应用程序的URL规则;
在Flask中,支持多种HTTP请求方法,如GET、POST、PUT、DELETE等;
并且允许为每种请求方法定义不同的处理函数,以及使用 methods参数为同一个 URL 路径定义多个请求方法。
Flask 支持的 HTTP 请求方式:
- GET: 用于请求数据。
- POST: 用于提交数据,通常用于表单提交。
- PUT: 用于更新资源。
- DELETE: 用于删除资源。
- HEAD: 与 GET 类似,但服务器只返回 HTTP 头部信息,不返回实际内容。
- OPTIONS: 用于获取目标资源所支持的通信选项。
- PATCH: 用于对资源进行部分更新。
from flask import Flask app = Flask(__name__) # 可以使用 methods 参数在路由装饰器中指定多个请求方法 @app.route('/example', methods=['GET', 'POST']) def example(): if request.method == 'GET': # 处理 GET 请求 return 'This is a GET request' elif request.method == 'POST': # 处理 POST 请求 return 'This is a POST request' if __name__ == '__main__': app.run(debug=True)
路由装饰器中的参数
Flask 的路由装饰器 @app.route() 和 @blueprint.route()路由蓝图有几个常用的参数:
rule: 指定路由规则的字符串,通常是路径模板,例如 '/hello'。
methods: 一个包含所支持 HTTP 请求方法的列表,如 ['GET', 'POST']。
endpoint: 指定路由的端点名称,用于在程序中唯一标识这个路由。如果不指定,Flask 会自动为路由生成一个端点名称。
strict_slashes: 如果设置为 True,则要求 URL 必须与规则完全匹配。例如,如果规则是 '/foo',那么 /foo/ 将不会匹配这个规则。默认为 False。
redirect_to: 如果提供了这个参数,当路由被访问时,将会重定向到指定的 URL。这通常用于旧 URL 的重定向。
subdomain: 指定子域名,例如 '.example.com'。这样,当访问 user.example.com 时,可以匹配到这个路由。
from flask import Flask app = Flask(__name__) @app.route('/users/', methods=['GET'], strict_slashes=True, endpoint='user_profile') def show_user_profile(username): # 显示用户资料 return f'User Profile for {username}' @app.route('/old-url', redirect_to='/new-url') def redirect_old_url(): # 重定向旧 URL 到新 URL pass @app.route('/new-url') def redirect_new_url(): # 返回新视图函数的处理结果 return f"new url return" if __name__ == '__main__': app.run(debug=True)
Flask 路由参数
类型 说明 string (默认) 仅可接受任何不包含斜杠的文本 int 仅可接受任何不包含斜杠的整数 float 仅可接受任何不包含斜杠的浮点数 path 类似string,但可以接受文件路径(包含斜杠) uuid 仅可接受任何不包含斜杠的uuid字符串 any 可以同时指定多种路径进行限定 re 通过继承BaseConverter实现自定义转换器实现正则匹配 from flask import Flask app = Flask(__name__) @app.route("/") def index(): return "Flask 路由参数" @app.route("/string//") # 声明了一个string类型的路由参数,这也是Flask中路由参数的默认类型 # 需要注意,视图函数中的参数需要和路由参数一致 def get_string(username): print(type(username), username) return f"姓名:{username}" @app.route("/int//") # 声明了一个int类型的路由参数,仅接受整数类型,传递其他类型时会抛出异常,哪怕传递是float类型 def get_int(age): print(type(age), age) return f"年龄:{age}" @app.route("/float//") def get_float(money): print(type(money), money) return f"存款:{money}" @app.route("/path//") def get_path(address): print(type(address), address) return f"地址:{address}" @app.route("/any//") def get_any(city): print(type(city), city) return f"城市:{city}" # 导入转换器基类 from werkzeug.routing import BaseConverter # 自定义转换器 class RegexConverter(BaseConverter): def __init__(self, url_map, *args): super(RegexConverter, self).__init__(url_map) # 将接受的第1个参数当作匹配规则进行保存 self.regex = args[0] # 添加转换器到默认的转换器字典中,并指定转换器使用时名字为:re app.url_map.converters['re'] = RegexConverter # 使用转换器去实现自定义匹配规则(当前此处定义的规则为:3位数字) @app.route('/user/') def user_info(user_id): return f"用户ID:{user_id}" if __name__ == '__main__': app.run(debug=True)
其实,Flask中内的的路由参数类型也是不同的转换器
# 系统自带的转换器具体使用方式在每种转换器的注释代码中有写,请留意每种转换器初始化的参数。 DEFAULT_CONVERTERS = { 'default': UnicodeConverter, 'string': UnicodeConverter, 'any': AnyConverter, 'path': PathConverter, 'int': IntegerConverter, 'float': FloatConverter, 'uuid': UUIDConverter, }
Flask 路由蓝图
Flask的路由蓝图(Blueprint)是一种组织和管理Flask应用中的路由和视图的方式。
它允许将相关的路由和视图分组到一个单独的模块或蓝图中,然后在主应用中注册这个蓝图。
这样可以使代码更加模块化和可维护。
路由蓝图的优点
- 模块化:通过将相关的路由和视图组织到一个蓝图中,可以将应用程序拆分成多个独立的模块,每个模块都有自己的路由和视图。这有助于保持代码的清晰和可维护性。
- 避免命名冲突:在Flask应用中,路由和视图的名称必须是唯一的。通过使用蓝图,可以在不同的蓝图中使用相同的路由和视图名称,而不会发生冲突。
- 注册蓝图:在主应用中,可以使用app.register_blueprint()方法将蓝图注册到应用中。注册时,你可以指定蓝图的前缀、子域名等参数,以便在应用中定位到该蓝图。
- 分组路由:在蓝图中,可以使用@blueprint.route()装饰器来定义路由。这样,所有在该蓝图下定义的路由都会自动带上蓝图的前缀。
路由蓝图的参数
- name:蓝图的名称。这个名称必须是唯一的,并且在 Flask 应用中用于标识这个蓝图。它通常是一个字符串,表示蓝图的名字。例如,'main' 或 'user'。
- import_name:蓝图所在的模块或包的名称。这个参数用于在蓝图内部查找资源和函数。通常,这个参数设置为 __name__,即当前模块的名称。
- static_folder:一个可选参数,指定静态文件文件夹的名称(默认为 'static')。这个文件夹通常包含 CSS、JavaScript 和图像文件等静态资源。
- static_url_path:一个可选参数,指定静态文件的 URL 路径(默认为 '/static')。这个路径用于生成静态文件的 URL。
- template_folder:一个可选参数,指定模板文件夹的名称(默认为 'templates')。这个文件夹通常包含 Flask 应用的 HTML 模板。
- url_prefix:一个可选参数,为蓝图中的所有路由添加前缀。例如,如果 url_prefix 设置为 '/api',那么蓝图中的路由 /hello 将被映射到 /api/hello。
- subdomain:一个可选参数,指定蓝图的子域名。例如,如果 subdomain 设置为 'admin',那么蓝图中的路由将只响应子域名为 admin 的请求。
Flask 路由蓝图结构
Flask 请求对象
在 Flask 框架中,Request对象是一个非常重要的全局对象;
它封装了来自客户端的 HTTP 请求的所有信息。
这个对象允许你访问请求的各个方面,如查询参数、表单数据、JSON 数据、头部信息、cookies 等。
属性 说明 url 当前请求的完整路径 method 当前请求的方法 headers 当前请求的http协议头部 form 当前请求的表单参数及其值的字典对象 args 当前请求的查询字符串的字典对象 values 当前请求包含所有数据的字典对象 json 如果mimetype是application/json,这个参数将会解析json数据,否则返回None cookies 当前请求的cookie名称和值的字典对象 files 当前请求与上传文件有关的数据 user_agent 当前请求的用户代理信息 remote_addr 当前请求的来源 from flask import Flask app = Flask(__name__) @app.route("/request", methods=["GET", "POST"]) def get_request(): print("请求体:", request) print("请求方法:", request.method) # GET请求的参数 print("请求参数:", type(request.args), request.args) # 类字典 # print("取参1个:", request.args.get("name")) # print("取参N个:", request.args.getlist("name")) # POST请求的参数 # print("请求参数:", request.form) # print("取参1个:", request.form.get("name")) # COOKIE # print("获取Cookies:", request.cookies) print("完整URL:", request.url) print("基础URL:", request.base_url) print("主机URL:", request.host_url) print("请求路径:", request.path) print("请求的客户端地址:", request.remote_addr) print("上传的文件:", request.files) print("请求头部:", request.headers) print("用户代理:", request.user_agent) # 包括浏览器和操作系统信息 return "request ok!" if __name__ == '__main__': app.run(debug=True)
Flask 响应对象
在 Flask 框架中,响应对象(Response Object)代表了一个 HTTP 响应;
这是 Flask 应用发送回客户端(通常是浏览器)的数据。
Flask 使用 Werkzeug 库来处理 HTTP 请求和响应,因此 Flask 的响应对象基于 Werkzeug 的 Response 类。
响应对象通常包含以下内容:
- 状态码:HTTP 响应的状态码,如 200(OK)、404(Not Found)等。
- 响应头:HTTP 响应头,如 Content-Type、Content-Length、Set-Cookie 等。
- 响应体:响应的正文内容,这可以是字符串、字节、文件对象、生成器或迭代器。
- MIME 类型:指定响应体的 MIME 类型,例如 text/html 或 application/json。
Flask 应用中的视图函数通常会返回一个字符串或一个元组,但 Flask 会自动将这个返回值转换成一个响应对象。
如果视图函数返回一个字符串,Flask 会创建一个包含该字符串的响应对象,并设置正确的 MIME 类型。
除了字符串,视图函数还可以返回以下几种类型的响应对象:
- Response 对象:可以直接返回一个 Werkzeug 的 Response 对象。
- 元组:返回一个包含响应体和状态码的元组 (response_body, status_code)。
- 元组(包含响应体、状态码和响应头):返回一个包含响应体、状态码和响应头的元组 (response_body, status_code, headers)。
- 生成器:返回一个生成器,Flask 会将生成器的内容作为响应体发送。
- 文件对象:返回一个文件对象,Flask 会将该文件的内容作为响应体发送。
- 重定向:使用 redirect() 函数可以返回一个重定向响应,将客户端重定向到另一个 URL。
- JSON 响应:使用 jsonify() 函数可以返回一个包含 JSON 数据的响应。
from flask import Flask, jsonify, redirect, Response, send_file app = Flask(__name__) @app.route('/') def index(): # 返回字符串 return 'Hello, World!' @app.route('/json') def json_response(): # 返回 JSON 响应 return jsonify({'message': 'Hello, JSON!'}) @app.route('/redirect') def redirect_response(): # 返回重定向响应 return redirect('/') @app.route('/file') def file_response(): # 返回文件响应 return send_file('example.txt', as_attachment=True) @app.route('/custom') def custom_response(): # 返回自定义的 Response 对象 response = Response('Custom Response', status=200, mimetype='text/plain') return response if __name__ == '__main__': app.run()
在Flask中的Response对象是用来处理和发送HTTP响应的关键组件,它允许设置响应的内容、状态码、头部信息等,也可以使用make_response函数来创建一个Response对象
Flask 会话保持
HTTP协议的两大特性:
1.无连接
- HTTP协议每次连接只处理一个HTTP请求,服务器处理完客户端的请求并且得到客户端的应答后,就会断开连接;
2.无状态
- 每次浏览器向服务器发送请求时,服务器不会记住之前的交互,每次请求都是独立且全新的,与前后请求无直接上下文联系。
状态保持的需求
- 然而,在现实生活中,许多应用都需要知道用户的浏览状态。
- 例如,一个在线购物网站可能需要知道用户是否已经登录,或者他们之前浏览过哪些商品。
- 这些信息对于提供个性化的体验、维护用户的会话或确保数据的安全性都至关重要。
状态保持的方法
为了满足这种需求,开发者采用了两种主要的方法来实现状态保持:
- 使用Cookie在客户端存储信息:Cookie是一种小型的文本文件,可以存储在用户的浏览器上。当浏览器再次请求同一个网站时,它会发送之前存储的Cookie,使服务器能够识别用户并恢复其状态。
- 使用Session在服务端存储信息:与Cookie不同,Session状态是存储在服务器端的。当用户首次访问时,服务器会为其创建一个唯一的Session ID,并将其发送到用户的浏览器,通常是作为Cookie。随后,浏览器在每次请求时都会带上这个ID,使服务器能够识别并恢复用户的状态。
Cookie 简介
Cookie概念
- Cookie是由服务器端创建并管理的,随后被发送给客户端(通常是用户的浏览器)。
- 浏览器一旦接收到这些Cookie,会在本地存储一段时间,通常是基于Cookie中设置的过期时间。
- 在此期间,每当浏览器向同一服务器发起请求时,它都会自动附带这些Cookie。
- 这些Cookie的目的是帮助服务器识别并跟踪用户的会话,从而提供个性化的服务或记住用户之前的操作,如登录状态、购物车内容等。
Cookie使用
- 在Flask中,可以通过直接操作响应对象(Response object)来设置Cookie;
- response.set_cookie()方法允许你为特定的响应对象设置Cookie;
- 当你调用response.set_cookie()时,你实际上是在告诉浏览器:“请存储这个信息,并在未来的请求中发送给我。这样,服务器就能够识别出用户。
这个方法接收多个参数,允许定义Cookie的名称、值、过期时间等属性,如下所示。
属性 描述 key Cookie的键名 value Cookie值 max_age cookie保存时间(秒), 关闭浏览器也会过期 expires 具体过期时间, 一个datetime对象 domain 设置Cookie可用域 secure 如果设置为True,仅HTTPS可用 httponly 禁止客户端的javascript读取Cookie Cookie使用示例代码
这段代码是一个简单的登录/注销系统的实现,它使用 cookie 来跟踪用户的登录状态。
当用户登录时,他们的用户名会被存储在一个 cookie 中,当用户访问首页时,这个用户名会被从 cookie 中取出并显示。
当用户注销时,cookie 会被删除,这样用户的登录状态就会失效。
main.py
import datetime from flask import Flask, render_template, request, redirect app = Flask(__name__) # 首页 @app.route("/home") def home(): # 4.获取cookie username = request.cookies.get("user") return render_template("home.html", username=username) # 登录 @app.route("/login", methods=["GET", "POST"]) def login(): if request.method == "GET": return render_template("login.html") elif request.method == "POST": pass # 1.获取前段提交过来的数据 username = request.form.get("username") password = request.form.get("password") # 2.模拟登录:账号密码验证 if username == "admin" and password == "123456": # 登录成功 response = redirect("/home") # 3.设置cookie(确保set_cookie方法调用是在返回响应对象response之前进行) # 默认关闭浏览器,cookie失效 # response.set_cookie("user", username) # 设置过期时间: # max_age(秒) = 3600秒 = 1小时 * 24 * 7 = 7天 # response.set_cookie("user", username, max_age=3600 * 24 * 7) # expires 指定日期 # 确保expires参数设置的日期是在未来 # 确保max_age和expires 参数没有同时被设置,因为同时设置可能会导致冲突 response.set_cookie("user", username, expires=datetime.datetime(2024, 12, 12)) return response else: return "账号或密码错误,请重试!" # 注销 @app.route("/logout") def logout(): response = redirect("/home") # 5.删除cookie response.delete_cookie("user") return response if __name__ == '__main__': app.run(debug=True)
home.py
首页
首页
{% if username %}当前登录账号:{{ username }}
{% else %} 登录 {% endif %}login.html
登录
登录
- 每次浏览器向服务器发送请求时,服务器不会记住之前的交互,每次请求都是独立且全新的,与前后请求无直接上下文联系。
- HTTP协议每次连接只处理一个HTTP请求,服务器处理完客户端的请求并且得到客户端的应答后,就会断开连接;
还没有评论,来说两句吧...