Flask简介
Flask是一个基于Python开发而且依赖jinja2模板和Werkzeug WSGI服务的一个微型Web框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,而后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,若是要返回给用户复杂的内容时,须要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。
Flask被设计为易于使用,同时也提供了扩展性,用户可以自由地选择将其与哪些第三方库集成。Flask是"微"框架,这意味着其核心功能非常有限,但可以通过一系列的扩展来增强功能。
Flask基本使用
安装与使用示例
pip install flask
让我们来看一下如何创建一个简单的Flask应用。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run()
在这段代码中,我们首先导入Flask模块,并创建一个Flask web服务器实例。然后,我们定义了一个路由(route),即/
。这个路由映射到一个函数hello_world
,当用户访问这个URL时,它会返回'Hello, World!'字符串。
Flask路由
Flask通过提供装饰器app.route
,使得定义路由变得简单易行。但你知道我们也可以通过app.add_url_rule
方法直接添加路由吗?这种方式提供了更多的灵活性,例如,可以为路由添加不同的HTTP方法。
from flask import Flask
app = Flask(__name__)
# @app.route('/index')
def index():
return 'hello'
# view_func必填
app.add_url_rule('/index', view_func=index)
if __name__ == '__main__':
app.run()
在上述代码中,app.add_url_rule
的第一个参数是URL规则,第二个参数是函数的别名,第三个参数是要映射的函数。
route参数
from flask import Flask
app = Flask(__name__)
"""
rule: 路由路径
methods: 请求方式
endpoint: 起别名, 用于反向解析. url_for('index')
strict_slashes: 设置路由是否为严格模式, True为严格模式, False为非严格模式, 默认为True
如果关闭 /hello和/hi/都被视为有效的URL
"""
@app.route('/index', methods=["GET", "POST"], endpoint='index', strict_slashes=True)
def index():
return "index"
# app.add_url_rule('/index', view_func=index)
"""
self.add_url_rule(rule, endpoint, f, **potion)参数以下
self: Flask类产生的对象(app)
rule: 路由
endpoint: 取别名, 若是为空, 用当前的函数名
methods: 请求方式
view_func: 取别名指向的函数(请求该路径, 要响应的函数)
"""
@app.route('/login')
def login():
return "login"
if __name__ == '__main__':
app.run()
路由装饰器
# 装饰器函数
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop("endpoint", None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
# 被装饰函数
@app.route('/login',methods=['POST', "GET"], endpoint='index')
def login():
return "hello world"
装饰器: 先执行装饰器, 运行里面的代码, 返回一个函数名
而后加括号, 把装饰器装饰的函数当成参数传递给函数,
返回一个被装饰器装饰的同名函数
路由跳转
from flask import Flask, url_for, redirect
app = Flask(__name__)
@app.route('/home', endpoint='home')
def home():
return 'Hello World!'
@app.route('/index')
def index():
# url_for函数用于建立URL的反向解析,它可以根据视图函数的名称生成对应的URL。
# 使用url_for可以有效地避免硬编码URL地址,提高代码的可维护性
return redirect(url_for('home'))
if __name__ == '__main__':
app.run()
路由参数
from flask import Flask, jsonify
app = Flask(__name__)
app.debug = True
USERS = {
1: {'name': '张三', 'age': 18, 'gender': '男', 'text': "道路千万条"},
2: {'name': '李四', 'age': 28, 'gender': '男', 'text': "安全第一条"},
3: {'name': '王五', 'age': 18, 'gender': '女', 'text': "行车不规范"},
}
@app.route('/detail/', methods=['GET'], endpoint='detail')
def detail(nid):
print(nid, type(nid))
return jsonify(USERS[nid])
if __name__ == '__main__':
app.run()
Flask模板
Flask使用jinja2模板库。这个库非常强大,可以让你在HTML中嵌入Python代码。下面的例子展示了如何在Flask应用中使用模板:
# python
from flask import Flask
from flask import render_template
app = Flask(__name__)
@app.route('/hello')
def hello():
name = '你好呀!'
return render_template('hello.html', name=name)
if __name__ == '__main__':
app.run()
render_template
函数用于渲染一个模板。它接收模板的名称和一些模板变量作为参数,返回生成的HTML内容。在模板中,你可以使用{{ name }}
来显示变量的值。
Title
{{ name }}
模板显示HTML
"""
一种: .py文件渲染标签, 导入Markup
二种: 前端页面{{ html|safe }}
"""
from flask import Flask, Markup, render_template
app = Flask(__name__)
app.debug = True
def func(st1, st2):
#Markup类用于在模板中输出HTML代码
''' flask 3的版本中不再提供 可以改成
from jinja2.utils import markupsafe
markupsafe.Markup(html)
''' # |safe 也可以讲字符串以html格式输出
return Markup(f"{st1} {st2}!")
@app.route('/index')
def index():
html = "you are beautiful!"
return render_template('index.html', func=func, html=html)
if __name__ == '__main__':
app.run()
html页面
Title
{{ func('hello', 'world') }}
{{ html|safe}}
{# safe过滤器用于告诉模板引擎将一个字符串作为原始的HTML代码进行渲染,而不是对其进行转义处理 #}
Flask 请求方式
from flask import request
@app.route('/', methods=['GET'])
def get_handler():
# 处理GET请求逻辑
return 'This is a GET request'
from flask import request
@app.route('/', methods=['POST'])
def post_handler():
# 处理POST请求逻辑
return 'This is a POST request'
from flask import request
@app.route('/', methods=['GET', 'POST'])
def handler():
if request.method == 'GET':
# 处理GET请求逻辑
return 'This is a GET request'
elif request.method == 'POST':
# 处理POST请求逻辑
return 'This is a POST request'
Flask请求与响应
from flask import Flask
from flask import request
from flask import make_response
from flask import render_template
from flask import redirect
请求
request.args # get请求提交的数据
# 用于获取GET请求中的查询参数。例如,对于URL example.com?name=John&age=25,可以使用request.args.get('name')来获取参数值 'John'。
request.form # post请求提交的数据
# 用于获取POST请求中的表单数据。当客户端向服务器发送一个POST请求并提交表单数据时,可以使用request.form.get('key')来获取表单字段的值。
request.values # post和get提交的数据都在
# 用于获取GET和POST请求中的所有参数值。既包括查询参数也包括表单数据。可以使用request.values.get('key')来获取参数值
request.cookies # 客户端携带cookie
# 用于获取客户端请求中携带的cookie信息。可以使用request.cookies.get('cookie_name')来获取特定cookie的值。
request.headers # 请求头
# 用于获取客户端请求的HTTP头信息。可以使用request.headers.get('header_name')来获取特定头字段的值。
request.path # 不带域名, 请求路径如: /index
# 获取当前请求的路径,不包含域名部分。例如,对于URL example.com/index,request.path 的值为 /index。
request.full_path # 不带域名, 带参数的请求路径
# 获取当前请求的路径,包含域名和参数部分。例如,对于URL example.com/index?name=John,request.full_path 的值为 /index?name=John。
request.url #带域名带参数的请求路径
# 获取当前请求的完整URL,包括域名和参数。例如,http://example.com/index?name=John。
request.base_url #带域名请求路径
# 获取当前请求的URL,不包含参数部分。例如,http://example.com/index。
request.url_root #域名
# 获取当前请求的域名部分。例如,http://example.com。
request.files # 获取上传文件
obj = request.files['the_file_name']
obj.save('/var/www/uploads/' + secure_filename(filename))
# 上传文件
# 用于获取客户端上传的文件。可以使用request.files['file_field_name']来访问上传的文件对象。上传的文件可以使用.save()方法保存到指定的路径。
响应
# 四种响应方式
return "字符串" # 直接返回字符串
return render_template('html模板路径',**{})# 返回HTML模板
return redirect('/index.html') # 跳转页面
return jsonify({'k1':'v1'}) # 返回json数据
# 更新响应体参数
response = make_response(render_template('index.html'))
response.delete_cookie('key')
response.set_cookie('key', 'value')
response.headers['X-Something'] = 'A value'
return response
"""
1. 通过调用make_response函数,创建一个响应对象,并将渲染后的index.html模板作为响应的内容。
2. 用delete_cookie方法从响应对象中删除名为 'key' 的cookie。这将告诉客户端删除该cookie。
3. 使用set_cookie方法向响应对象中设置一个名为 'key' 的cookie,并将其值设置为 'value'。
4 通过修改headers属性,向响应中添加一个名为 'X-Something' 的自定义头,并将其值设置为 'A value'
"""
Flask的配置文件
from flask import Flask
app = Flask(__name__)
# 配置文件
# app.debug = True
# app.secret_key = '123123'
# 以字典的形式
# app.config['DEBUG'] = True
# 以文件的方式
# app.config.from_pyfile('settings.py')
# 以类的形式(推荐使用, 好比: 上线和线下所用的配置文件不同)
# 创建一个配置类
class DevelopmentConfig:
DEBUG = True
SECRET_KEY = 'your_secret_key'
# 使用 app.config.from_object 加载配置
app.config.from_object(DevelopmentConfig)
@app.route('/login')
def login():
print("hello world")
return 'ok'
if __name__ == '__main__':
app.run()
各类配置
# 是否开启 Debug 模式
DEBUG = False
# 是否开启测试模式
TESTING = False
# 异常是否传递给上层应用
PROPAGATE_EXCEPTIONS = None
# 异常时上下文是否保留
PRESERVE_CONTEXT_ON_EXCEPTION = None
# 密钥(用于会话等加密)
# SECRET_KEY = None
# 会话的生命周期
# PERMANENT_SESSION_LIFETIME = timedelta(days=31)
# 是否启用 X-Sendfile 响应头
USE_X_SENDFILE = False
# 日志器名称
# LOGGER_NAME = None
# 请求日志处理策略
# LOGGER_HANDLER_POLICY = 'always'
# 服务器名称
# SERVER_NAME = None
# 应用程序根目录
# APPLICATION_ROOT = None
# 会话的 Cookie 名称
SESSION_COOKIE_NAME = 'session'
# 会话的 Cookie 域名
SESSION_COOKIE_DOMAIN = None
# 会话的 Cookie 路径
SESSION_COOKIE_PATH = None
# 会话的 Cookie 是否只能通过 HTTP 访问
SESSION_COOKIE_HTTPONLY = True
# 会话的 Cookie 是否启用安全标志(HTTPS)
SESSION_COOKIE_SECURE = False
# 每个请求是否刷新会话
SESSION_REFRESH_EACH_REQUEST = True
# 最大接受的请求体大小
# MAX_CONTENT_LENGTH = None
# 静态文件的缓存时间
# SEND_FILE_MAX_AGE_DEFAULT = timedelta(hours=12)
# 是否捕获损坏的请求错误
TRAP_BAD_REQUEST_ERRORS = False
# 是否捕获 HTTP 异常
TRAP_HTTP_EXCEPTIONS = False
# 是否解释模板加载
EXPLAIN_TEMPLATE_LOADING = False
# 首选 URL 方案
PREFERRED_URL_SCHEME = 'http'
# JSON 是否使用 ASCII 编码
JSON_AS_ASCII = True
# JSON 是否按键排序
JSON_SORT_KEYS = True
# JSON 是否格式化后输出
JSONIFY_PRETTYPRINT_REGULAR = True
# JSON 的 MIME 类型
JSONIFY_MIMETYPE = 'application/json'
# 模板是否自动重新加载
# TEMPLATES_AUTO_RELOAD = None
Flask闪现
闪现: 可用于记录和获取日志
1. 若是要用flash就必须设置app.secret_key = ''
2. 日志数据只能获取一次,在取就没有了
3. 可以通过 flash('普通讯息',category="info"),对信息作分类
4. get_flashed_messages(with_categories=True,category_filter=("error",)),with_categories以键值对的形式获取
咱们设置闪现,category_filter=("error",)进行分类信息的过滤前端
from flask import Flask, flash, get_flashed_messages
app = Flask(__name__)
app.debug = True
app.secret_key = 'abcdefg'
'''
secret_key随便定义一个字符串并不是一个好的做法。为了确保会话数据的安全性,应该使用足够安全和复杂的字符串。可以使用随机字符串生成工具来生成一个随机的密钥,或者使用诸如 UUID、哈希函数等机制来生成一个唯一的密钥。
'''
@app.route('/index')
def index():
# flash(message, category)
flash("超时错误", category="error")
flash('普通讯息', category="info")
return ""
@app.route('/inner')
def inner():
# 需要先运行index路由获取信息
# with_categories=False 表示只显示信息, 不显示分类。 category_filter 代表获取信息类型
data = get_flashed_messages(with_categories=False, category_filter=("error", "info"))
data1 = get_flashed_messages(with_categories=True, category_filter=("error", "info"))
print(data)
print(data1)
return ""
if __name__ == '__main__':
app.run()
Flask表单处理
Flask-WTF是Flask中用于处理Web表单的扩展库。它基于WTF Python,一个处理表单数据的Python库。Flask-WTF还具有CSRF(跨站请求伪造)保护的功能。
让我们看一个简单的例子:
from flask import Flask, render_template
from flask_wtf import FlaskForm # pip install flask-wtf
from wtforms import StringField
from wtforms.validators import InputRequired
app = Flask(__name__)
app.config['SECRET_KEY'] = 'abcd'
class MyForm(FlaskForm):
name = StringField('Name', validators=[InputRequired()])
@app.route('/', methods=['GET', 'POST'])
def submit():
form = MyForm()
if form.validate_on_submit():
name = form.name.data
return f'Hello, {name}!'
return render_template('hello.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
validators=[InputRequired()]
是在 Flask-WTF 表单中使用的验证器之一,它表示在验证输入时要求字段的值不能为空。
在这个例子中,我们定义了一个表单类MyForm
,包含一个name
字段。然后,我们在submit
路由中创建了一个该类的实例,并检查表单是否通过验证。如果表单有效,我们就返回一条欢迎信息;否则,我们就渲染一个表单模板。
Submit Form
Submit Form
{{ form.hidden_tag() }}
{{ form.name.label }}
{{ form.name(size=20) }}
{% for error in form.name.errors %}
{{ error }}
{% endfor %}
-
{{ url_for('submit') }}:这是一个动态生成的 URL,它将表单提交到submit视图函数。url_for()函数会根据给定的视图函数名称生成对应的 URL。在这种情况下,它会生成一个指向submit视图函数的 URL,用于处理表单的提交。
-
{{ form.hidden_tag() }}:这是一个 Flask-WTF 表单生成的隐藏字段,用于防止跨站请求伪造(CSRF)攻击。在提交表单时,这个隐藏字段会被包含在表单数据中。
-
{{ form.name.label }}:这是表单字段name的标签。form.name表示这个字段在生成的表单中的位置。
-
{{ form.name(size=20) }}:这是表单字段name的输入框,其中name是输入框的名称,size是输入框的大小设置。在这个例子中,name字段的输入框大小被设置为20。
-
{% for error in form.name.errors %} 和 {{ error }}:这是一个用于迭代显示验证错误的循环。form.name.errors返回一个列表,其中包含了针对name字段的验证错误消息。该代码块将循环遍历错误列表,并对每个错误以红色文本的形式显示出来。
Flask蓝图
Flask的蓝图功能让我们能够组织更大、更复杂的应用程序。你可以将蓝图视为Flask应用程序的一个子集,它可以拥有自己的路由、模板和静态文件。
下面是一个简单的例子:app.py:
from flask import Flask
from blueprints.page import simple_page
app = Flask(__name__)
app.register_blueprint(simple_page)
if __name__ == '__main__':
app.run(debug=True)
blueprints/page.py:
from flask import Blueprint
simple_page = Blueprint('simple_page', __name__)
@simple_page.route('/')
def show(page):
return f'Page {page}'
蓝图的一个主要作用是将不同功能的代码组织到不同的文件中,以实现功能的模块化和路由函数的区分。
通过使用蓝图,你可以将不同的功能模块拆分到不同的文件中,比如将用户认证相关的代码放在一个文件,将文章管理相关的代码放在另一个文件。这样做的好处是可以使代码更加结构化,便于管理和维护。
Flask错误处理
Flask允许我们自定义错误处理函数,当特定的HTTP错误发生时,我们可以返回自定义的响应。以下是如何为404错误定义自定义处理函数的示例:
@app.errorhandler(404)
def page_not_found(error):
return 'This page does not exist', 404
在这个例子中,我们使用app.errorhandler
装饰器注册一个新的错误处理函数。当404错误发生时,它将返回一个自定义的错误消息。
Flask请求钩子
Flask提供了几个装饰器,我们可以使用它们来注册在处理请求的不同阶段调用的函数。这些装饰器包括before_first_request
、before_request
、after_request
和teardown_request
。
@app.before_first_request
def before_first_request():
print("第一次请求")
@app.before_request
def before_request():
print("开始请求")
@app.after_request
def after(response):
print("请求之后")
return response
# 有没有异常都会执行该函数, 没有e为None, 有e为错误信息
@app.teardown_request
def tear(e):
print(e)
在以上例子中,装饰器的函数将在每个请求时执行。
Flask 中间键
在 Flask 中,中间件是对 WSGI 规范的实现,用于在请求被处理之前和之后执行一些额外的操作。中间件可以用于修改请求或响应、记录日志、执行身份验证等
from flask import Flask
app = Flask(__name__)
app.debug = True
class MyMiddleware:
def __init__(self, wsgi_app):
self.wsgi_app = wsgi_app
def __call__(self, environ, start_response):
print('以前操作')
res = self.wsgi_app(environ, start_response)
print('以后操作')
return res
app.wsgi_app = MyMiddleware(app.wsgi_app)
@app.route('/index')
def index():
print('ok1')
return "ok1"
@app.route('/inner')
def inner():
print('ok2')
return "ok2"
if __name__ == '__main__':
app.run()
Flask中的Cookies和Sessions
在Web开发中,我们常常需要存储用户的信息,例如用户的偏好设置或者登录状态。Flask提供了Cookies和Sessions两种方式来完成这个任务。
下面是如何在Flask中设置和读取cookie的例子:
@app.route('/set')
def setcookie():
resp = make_response('Setting cookie!')
resp.set_cookie('username', 'the username')
return resp
'''
resp = make_response(render_template('index.html'))
resp.set_cookie('username', 'John')
return resp
'''
@app.route('/get')
def getcookie():
username = request.cookies.get('username')
return 'The username is ' + username
在上述例子中,setcookie
路由设置了一个cookie,名为username
,getcookie
路由读取并返回了这个cookie的值。
"""
session和cookie
app.session_interface这里面看
存session:
1. 调用save_session,将咱们的session加密的val,读取配置文件['SESSION_COOKIE_NAME']获得key
2. 将1种的key,val存储到cookies
取session;
1. 获取request里面的cookies,获取里面key,这个key就是['SESSION_COOKIE_NAME'],值就是加密的值
2. 对该值进行解密
"""
from flask import Flask, session
app = Flask(__name__)
app.debug = True
# 在浏览器存储的key名字
app.config['SESSION_COOKIE_NAME'] = 'session'
# 秘钥
app.secret_key = 'ahsodhfb'
# 存
@app.route('/index')
def index():
session['hello'] = 'world'
return 'ok'
# 取
@app.route('/login')
def login():
print(session.get('hello'))
return 'I am fine'
if __name__ == '__main__':
app.run()
在 Flask 中,你可以通过设置 Cookie 和 Session 的过期时间来定义它们的时限。
设置 Cookie 的时限:
通过 set_cookie()
方法可以设置 Cookie 的过期时间。它接受一个可选的 expires
参数,用于指定 Cookie 的失效时间。expires
参数可以是一个 datetime
对象,表示具体的失效时间;也可以是一个字符串,表示相对于当前时间的时间间隔。如果不设置 expires
参数,默认情况下,Cookie 是会话性的,即在浏览器关闭时失效。
以下是一个示例,在设置 Cookie 时指定过期时间:
from flask import Flask, make_response, request
import datetime
app = Flask(__name__)
@app.route('/')
def index():
resp = make_response('Hello, world!')
expires = datetime.datetime.now() + datetime.timedelta(days=30)
resp.set_cookie('username', 'John', expires=expires)
return resp
if __name__ == '__main__':
app.run()
在这个示例中,通过 expires
参数将 Cookie 的过期时间设置为当前时间加上 30 天。这样,浏览器在存储这个 Cookie 后,将会在 30 天后自动将其删除。
设置 Session 的时限:
Flask 中的会话默认情况下是永久会话,即会持久保留在服务器端,直到手动删除或超过设定的失效时间。你可以通过设置 permanant_session_lifetime
属性来定义会话的过期时间。
以下是一个示例,在 Flask 应用中设置会话的过期时间为 2 小时:
from flask import Flask, session
app = Flask(__name__)
app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(hours=2)
@app.route('/')
def index():
session.permanent = True # 在会话中设置 permanent 属性为 True
session['username'] = 'John'
return 'Hello, world!'
if __name__ == '__main__':
app.run()
在这个示例中,我们使用 app.config['PERMANENT_SESSION_LIFETIME']
设置会话的过期时间为 2 小时。然后,在请求处理函数中,我们将会话的 permanent
属性设置为 True
,表示这个会话是持久会话,将会根据设定的过期时间进行失效。如果不设置 permanent
属性,默认情况下会话是非持久的,即浏览器关闭时失效。
通过设置 Cookie 和 Session 的过期时间,可以根据需要控制它们的时限,使其在指定时间后失效,增加应用的安全性和用户体验。