【Flask 系统教程 6】进阶操作

Flask操作cookie

在 Flask 中操作 Cookie 是相对简单的。Cookie 是一种存储在用户计算机上的小型数据片段,由服务器发送到用户浏览器,然后在每次请求时由浏览器发送回服务器。在 Flask 中,你可以使用 request 对象来读取 cookie,使用 response 对象来设置 cookie。

下面是在 Flask 中进行 Cookie 操作的基本示例:

from flask import Flask, request, make_responseapp = Flask(__name__)@app.route('/')
def index():# 读取名为 'username' 的 cookieusername = request.cookies.get('username')return f'Hello {username}'@app.route('/setcookie/<username>')
def setcookie(username):# 创建一个 response 对象resp = make_response('Cookie 设置成功')# 设置名为 'username' 的 cookieresp.set_cookie('username', username)return resp@app.route('/deletecookie')
def deletecookie():# 创建一个 response 对象resp = make_response('Cookie 已删除')# 删除名为 'username' 的 cookieresp.delete_cookie('username')return respif __name__ == '__main__':app.run(debug=True)

在上面的示例中,有三个路由:

  1. / 路由用于读取名为 ‘username’ 的 cookie,并返回相应的问候信息。
  2. /setcookie/<username> 路由用于设置名为 ‘username’ 的 cookie,其中 <username> 是要设置的用户名。
  3. /deletecookie 路由用于删除名为 ‘username’ 的 cookie。

设置cookie有效期

  • 使用max_age参数

在 Flask 中设置 Cookie 的有效期可以在设置 Cookie 时提供 max_age 参数,表示 Cookie 的过期时间 (以秒为单位) 。下面是一个示例,演示了如何在 Flask 中设置带有有效期的 Cookie:

from flask import Flask, make_responseapp = Flask(__name__)@app.route('/setcookie')
def setcookie():# 创建一个 response 对象resp = make_response('Cookie 设置成功')# 设置名为 'username' 的 cookie,并指定有效期为一小时resp.set_cookie('username', 'John', max_age=3600)return respif __name__ == '__main__':app.run(debug=True)

在上面的示例中,我们设置了名为 ‘username’ 的 Cookie,其值为 ‘John’,并且指定了有效期为一小时(3600 秒)。


  • 使用 expires 参数

在 Flask 中,你可以使用 expires 参数来设置 Cookie 的到期时间。expires 参数接受一个 datetime 对象,表示 Cookie 的过期时间。下面是一个示例,演示了如何在 Flask 中设置带有到期时间的 Cookie:

from flask import Flask, make_response
from datetime import datetimeapp = Flask(__name__)@app.route('/setcookie')
def setcookie():# 创建一个 response 对象resp = make_response('Cookie 设置成功')# 设置名为 'username' 的 cookie,并指定到期时间为2024年6月1日expires = datetime(2024, 6, 1)resp.set_cookie('username', 'John', expires=expires)return respif __name__ == '__main__':app.run(debug=True)

在上面的示例中,我们设置了名为 ‘username’ 的 Cookie,其值为 ‘John’,并且指定了到期时间为2024年6月1日。

如果同时使用了max_ageexpires两个参数,会以max_age为准

Flask操作session

在Flask中,Session 是一种在客户端和服务器之间存储信息的机制,可以跟踪用户的会话状态。在 Flask 中操作 Session 分为设置 Session、读取 Session 和删除 Session 三个主要步骤。

Flask设置Session

要在 Flask 中设置 Session,需要使用 Flask 提供的 session 对象。可以像字典一样对其进行操作来设置会话变量。首先,需要安装 Flask-Session 扩展来支持 Session 功能。

from flask import Flask, sessionapp = Flask(__name__)
app.secret_key = 'your_secret_key' # 设置盐参数(或者叫秘钥)@app.route('/')
def index():session['username'] = 'user123'return 'Session set successfully'if __name__ == '__main__':app.run(debug=True)

Flask读取Session

要读取 Session 中的值,只需通过键来访问 session 对象即可。

from flask import Flask, sessionapp = Flask(__name__)
app.secret_key = 'your_secret_key'@app.route('/')
def index():username = session.get('username')return f'Hello {username}'if __name__ == '__main__':app.run(debug=True)

Flask删除Session

要删除 Session 中的值,可以使用 pop() 方法或 clear 关键字。

  • pop指定键名
  • clear清除所有
from flask import Flask, sessionapp = Flask(__name__)
app.secret_key = 'your_secret_key'@app.route('/')
def index():session.pop('username', None)  # 删除名为 'username' 的 Session# 或者使用 del session['username']return 'Session deleted successfully'@app.route('/del_all')
def index():session.clear()  # Session中的所有内容return 'Session deleted successfully'if __name__ == '__main__':app.run(debug=True)

这就是在 Flask 中操作 Session 的基本方法。记住,为了保护 Session 数据的安全,务必在 Flask 应用程序中设置一个密钥,这个密钥会被用来签名 Session 数据。

设置session的有效期

可以通过设置 session.permanent来设置session有效期,设置为true之后,实际不是永久,默认保存31天,还可以通过app.config["PERMANENT_SESSION_LIFETIME"]参数来自定义时间。

from datetime import timedeltafrom flask import Flask, sessionapp = Flask(__name__)# 设置session的密钥
app.secret_key = 'your_secret_key'# 设置session有效期为一天
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(days=1)@app.route('/')
def index():# 设置session变量 session.permanent = True  # 启用设置有效期session['user'] = 'example_user'return 'Session set'@app.route('/get_session')
def get_session():# 获取session变量user = session.get('user', None)return 'Session user: {}'.format(user)if __name__ == '__main__':app.run(debug=True)

使用session实现免登录

使用session实现免登录功能是一种常见的做法,特别是在Web应用中。通过session,你可以在用户登录后存储相关的身份验证信息,然后在用户会话期间保持其登录状态,而无需用户重复登录。

下面是一个简单的示例,演示如何使用session实现免登录功能:

from flask import Flask, session, redirect, url_for, requestapp = Flask(__name__)# 设置session的密钥
app.secret_key = 'your_secret_key'@app.route('/')
def index():if 'username' in session:return 'Logged in as {}'.format(session['username'])return 'You are not logged in'@app.route('/login', methods=['POST'])
def login():if request.method == 'POST':# 假设这里有一个验证用户的过程# 如果验证成功,将用户名存储在session中session['username'] = request.form['username']return redirect(url_for('index'))@app.route('/logout')
def logout():# 退出登录,清除sessionsession.pop('username', None)return redirect(url_for('index'))if __name__ == '__main__':app.run(debug=True)

在这个示例中,用户在登录后,其用户名将存储在session中。在每次请求中,Flask会检查session中是否存在用户名,如果存在,就会认为用户已经登录。如果用户点击了退出登录的链接,则会清除session中的用户名,用户将被重定向到未登录状态下的页面。

通过这种方式,用户可以在登录一次后,保持其登录状态,直到他们主动选择退出登录为止。


g对象的使用

在Flask中,g对象是一个特殊的全局变量,用于在同一请求处理过程中的不同函数之间共享数据。g对象的作用类似于全局变量,但它只在同一请求期间有效,不同请求之间的g对象是独立的g对象通常用于在请求处理过程中存储临时数据或共享状态。

下面是一些使用g对象的常见场景和示例:

  1. 存储临时数据:你可以使用g对象在请求处理过程中存储临时数据,以便在不同的函数之间共享。例如,在请求开始时从数据库加载一些数据,并在请求处理过程中多次使用它们。
from flask import Flask, gapp = Flask(__name__)# 在请求处理前加载一些数据,并存储在g对象中
@app.before_request
def load_data():g.user = {'username': 'john', 'email': 'john@example.com'}# 在请求处理中使用g对象中的数据
@app.route('/')
def index():user = g.userreturn f'Hello, {user["username"]}'if __name__ == '__main__':app.run(debug=True)
  1. 共享状态信息:你可以使用g对象在请求处理过程中共享状态信息,例如数据库连接、用户身份验证信息等。这样可以避免在每个函数中重复创建和传递这些信息。
from flask import Flask, g
import sqlite3app = Flask(__name__)
app.config['DATABASE'] = '/path/to/database.db'# 在请求处理前连接数据库,并存储连接对象在g对象中
def get_db():if 'db' not in g:g.db = sqlite3.connect(app.config['DATABASE'])return g.db# 在请求处理结束后关闭数据库连接
@app.teardown_appcontext
def close_db(error):if hasattr(g, 'db'):g.db.close()@app.route('/')
def index():db = get_db()# 在请求处理中使用g对象中存储的数据库连接# 这里假设有一些数据库操作return 'Hello from index'if __name__ == '__main__':app.run(debug=True)

通过使用g对象,你可以在请求处理过程中方便地共享数据和状态信息,而无需将它们传递给每个函数。这样可以简化代码,并使得在同一请求期间的不同函数之间共享数据更加方便。

Flask中信号的使用

Flask中的信号使用是基于第三方模块blinker的,详情请看我的另一篇博客

Flask中的内置信号

Flask中的内置信号是一种事件通知机制,允许开发者在特定的情况下执行自定义的操作。以下是关于Flask内置信号的介绍:

  1. template_rendered:当模板渲染完成后发送的信号。可以用来执行与模板渲染相关的后处理操作。

  2. before_render_template:在模板渲染之前发送的信号。这允许开发者在模板渲染之前执行一些准备工作或修改模板渲染上下文。

  3. request_started:在请求开始之前发送的信号,即在到达视图函数之前。可以用于执行与请求开始相关的操作,例如记录请求信息或验证请求。

  4. request_finished:在请求处理完成,但在响应发送给客户端之前发送的信号。这个信号可以用于执行与请求结束相关的操作,如日志记录或资源清理。

  5. request_tearing_down:在请求对象被销毁时发送的信号。即使在请求过程中发生异常,也会发送该信号。可以用于执行与请求销毁相关的清理操作。

  6. got_request_exception:在请求过程中抛出异常时发送的信号。异常本身通过exception参数传递给订阅的函数。通常用于记录网站异常信息或执行异常处理逻辑。

  7. appcontext_tearing_down:在应用上下文被销毁时发送的信号。可以用于执行与应用上下文销毁相关的清理操作。

  8. appcontext_pushed:在应用上下文被推入到栈上时发送的信号。可以用于执行与应用上下文推入相关的初始化操作。

  9. appcontext_popped:在应用上下文被推出栈时发送的信号。可以用于执行与应用上下文推出相关的清理操作。

  10. message_flashed:调用了Flask的flash方法时发送的信号。可以用于在消息被闪现时执行特定的操作,如将消息记录到日志中。

这些内置信号提供了灵活的扩展点,使开发者能够在Flask应用的不同阶段执行自定义逻辑,从而实现更高级的功能或增强应用的可维护性和可扩展性。

内置信号的使用案例

选择got_request_exception信号作为案例,这个信号在请求处理过程中抛出异常时发送。一个常见的用例是记录网站异常信息到日志中。下面是一个简单的示例:

from flask import Flask
from flask.signals import got_request_exceptionapp = Flask(__name__)def log_exception(sender, exception, **extra):# 将异常信息记录到日志中app.logger.error('Exception occurred during request: %s', exception)# 订阅(got_request_exception)信号,当异常发生时调用log_exception函数
got_request_exception.connect(log_exception, app)@app.route('/')
def index():# 引发一个异常,模拟请求处理过程中出现的异常1 / 0if __name__ == '__main__':app.run(debug=True)

在这个例子中,我们创建了一个Flask应用,并定义了一个log_exception函数来记录异常信息到应用的日志中。然后,我们使用connect()方法来监听got_request_exception信号,并将其与log_exception函数关联起来。当请求处理过程中发生异常时,log_exception函数会被调用,并将异常信息记录到应用的日志中。

通过这种方式,我们可以方便地跟踪和记录应用中的异常,以便及时发现和解决问题。

WTForms的使用

。WTF(WTForms)是一个强大的Python表单库,常常用来在后端进行数据的校验

首先,确保你已经安装了Flask-WTF。你可以使用pip进行安装:

pip install Flask-WTF

下面是一个简单的示例,演示如何使用Flask-WTF创建一个简单的登录表单:

from flask import Flask, render_template, request
from wtforms import Form, StringField
from wtforms.validators import Length, EqualToapp = Flask(__name__)@app.route('/')
def index():return 'Hello! 'class RegisterForm(Form):uname = StringField(validators=[Length(min=2, max=10, message='用户名长度2-10之间')])pwd = StringField(validators=[Length(min=2, max=10)])pwd2 = StringField(validators=[Length(min=2, max=10), EqualTo('pwd', message='2次密码不一致')])@app.route('/register/', methods=['GET', 'POST'])
def register():if request.method == 'GET':return render_template('register.html')else:form = RegisterForm(request.form)if form.validate():  # 验证成功:True, 失败:Falsereturn '验证成功!'else:return f'验证失败!{form.errors}'if __name__ == '__main__':app.run(debug=True)

使用方法

  • 创建自定义类,需要继承自wtforms.Form
  • 添加校验字段(unamepwdpwd2),必须和表单的name值保持一致。
  • Length用来校验长度,message可以设置错误提示,EqualTo用来判断二者是否一致
  • 通过RegisterForm.validate()判断校验结果
  • 通过RegisterForm.errors获取错误信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>某系统注册页面</title>
</head>
<body><form action="/register/" method="post"><table><tr><th>用户名:</th><td><input type="text" name="uname"></td></tr><tr><th>密码:</th><td><input type="password" name="pwd"></td></tr><tr><th>确认密码:</th><td><input type="password" name="pwd2"></td></tr><tr><td></td><td><input type="submit" value="注册"></td></tr></table></form>
</body>
</html>

这是一个简单的注册案例,检验了账号密码长度以及密码的两次密码的一致。

WTForm的常用验证器

在 Flask 中使用 WTForms 验证器进行数据验证时,你可以根据需要选择以下常用验证器:

  1. Length: 字符串长度限制,可设置最小值和最大值。

    username = StringField(validators=[Length(min=3, max=10, message="用户名长度必须在3到10位之间")])
    
  2. EqualTo: 验证数据是否和另外一个字段相等,常用于密码和确认密码两个字段是否相等。

    password_repeat = StringField(validators=[Length(min=6, max=10), EqualTo("password")])
    
  3. Email: 验证上传的数据是否为邮箱数据格式。

    email = StringField(validators=[Email()])
    
  4. InputRequired: 验证该项数据为必填项,即要求该项非空。

    username = StringField(validators=[input_required()])
    
  5. NumberRange: 数值的区间,可设置最小值和最大值限制,如果处在这两个数字之间则满足。

    age = IntegerField(validators=[NumberRange(12, 18)])
    
  6. Regexp: 使用正则表达式进行验证,如验证手机号码。

    phone = StringField(validators=[Regexp(r'1[34578]\d{9}')])
    
  7. URL: 必须是 URL 的形式。

    home_page = StringField(validators=[URL()])
    

自定义验证器

你可以按照以下步骤来实现自定义验证器:

  1. 创建一个基于 WTForms 的自定义验证器类。
  2. 在类中定义以 validate_字段名(self, field) 命名规则的验证方法。
  3. 在验证方法中,使用 field.data 获取字段的值,并进行验证。
  4. 如果验证失败,抛出 wtforms.validators.ValidationError 异常,并传入验证失败的信息。

下面是一个示例代码:

from flask import Flask, request, render_template
from wtforms import Form, IntegerField
from wtforms.validators import InputRequired, ValidationErrorapp = Flask(__name__)class MyForm(Form):custom_field = IntegerField('Custom Field', validators=[InputRequired()])def validate_custom_field(self, field):value = field.data# 示例验证条件:如果字段值小于0,则抛出异常if value < 0:raise ValidationError('字段值必须大于等于0')@app.route('/', methods=['GET', 'POST'])
def index():form = MyForm(request.form)if request.method == 'POST' and form.validate():# 处理表单提交逻辑return '表单提交成功!'return render_template('index.html', form=form)if __name__ == '__main__':app.run(debug=True)

此处自定义了一个验证validate_custom_field,校验时自动执行validate_开头的函数

<!DOCTYPE html>
<html>
<head><title>My Form</title>
</head>
<body><h2>My Form</h2><form method="POST">{{ form.csrf_token }}<p>{{ form.custom_field.label }}<br>{{ form.custom_field() }}{% if form.custom_field.errors %}<span style="color: red;">{{ form.custom_field.errors[0] }}</span>{% endif %}</p><p><input type="submit" value="Submit"></p></form>
</body>
</html>

WTF使用模板渲染

这段代码主要展示了如何使用Flask和WTForms来创建一个简单的表单,并使用WTForms的渲染模板功能来渲染表单到HTML页面上。以下是对代码的整理:

app.py:

from flask import Flask, render_template
from formscheck import CreateFormapp = Flask(__name__)# 定义路由,用于显示表单页面
@app.route('/createform/')
def createform():form = CreateForm()return render_template('create_form.html', form=form)if __name__ == '__main__':app.run(debug=True)

formscheck.py:

from wtforms import Form, StringField, IntegerField, BooleanField, SelectField
from wtforms.validators import InputRequired, NumberRange# 定义表单类
class CreateForm(Form):uname = StringField("用户名:", validators=[InputRequired()])age = IntegerField("年龄:", validators=[NumberRange(18, 40)])remember = BooleanField("记住我:")addr = SelectField('地址:', choices=[('bj', "北京"), ('sj', '上海'), ('tj', '天津')])

create_form.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>.classname {background: red;}</style>
</head>
<body><h2>WTForms创建表单</h2><form action="#" method="post"><table><tr><td>{{ form.uname.label }}</td><td>{{ form.uname(class='classname') }}</td></tr><tr><td>{{ form.age.label }}</td><td>{{ form.age() }}</td></tr><tr><td>{{ form.remember.label }}</td><td>{{ form.remember() }}</td></tr><tr><td>{{ form.addr.label }}</td><td>{{ form.addr() }}</td></tr><tr><td></td><td><input type="submit" value="提交"></td></tr></table></form>
</body>
</html>

自动对验证器类渲染解析并使用在模板中

  • 效果

在这里插入图片描述

使用WTF进行文件验证

当涉及到文件上传时,验证是非常重要的,可以确保上传的文件符合期望的格式、大小等规范。你可以使用Flask-WTF来简化表单验证的过程。下面是如何使用WTF对文件进行验证:

import osfrom flask import Flask, render_template, send_from_directory
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired, FileAllowed
from werkzeug.utils import secure_filenameapp = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['UPLOAD_FOLDER'] = 'uploads'  # 设置存储路径class UploadForm(FlaskForm):file = FileField('File', validators=[FileRequired(),  # 验证文件不能为空FileAllowed(['txt', 'pdf', 'doc', 'docx'], 'Allowed file types: txt, pdf, doc, docx')  # 验证文件后缀名])@app.route('/upload', methods=['GET', 'POST'])
def upload_file():form = UploadForm()if form.validate_on_submit():file = form.file.datafilename = secure_filename(file.filename)if not os.path.exists(os.path.join(app.config['UPLOAD_FOLDER'])):os.mkdir(os.path.join(app.config['UPLOAD_FOLDER']))file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))return 'File uploaded successfully'return render_template('upload.html', form=form)@app.route('/uploads/<filename>')
def uploaded_file(filename):return send_from_directory(app.config['UPLOAD_FOLDER'], filename)if __name__ == '__main__':app.run(debug=True)

这里我们引入了FlaskForm,它是WTF表单的基类,用于创建表单。FileField表示一个文件上传字段,它的validators参数用于添加验证规则。在这个例子中,我们使用FileRequired()确保文件字段不为空,并使用FileAllowed()指定允许上传的文件类型。

在HTML模板upload.html中,你只需要使用form.file来渲染文件上传字段即可:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>File Upload</title>
</head>
<body><h1>Upload File</h1><form method="post" enctype="multipart/form-data">{{ form.hidden_tag() }}{{ form.file.label }} {{ form.file() }}<input type="submit" value="Upload">{% if form.file.errors %}<ul>{% for error in form.file.errors %}<li>{{ error }}</li>{% endfor %}</ul>{% endif %}</form>
</body>
</html>

这样,你就可以在上传文件时进行验证,并确保上传的文件符合预期的要求。

Flask-RESTful

介绍RESTful

RESTful是一种基于REST架构风格设计的软件架构风格,它是Representational State Transfer(表征状态转移)的缩写。RESTful架构风格在设计网络应用程序时,采用了一系列约束和原则,使得系统更加简单、可扩展、可维护和可理解。下面是RESTful的一些关键特性和原则:

  1. 资源(Resources):在RESTful架构中,所有的内容都被抽象为资源,每个资源都可以通过唯一的URI来标识。例如,一个博客系统中的文章、评论、用户等都可以是资源。

  2. 表征(Representation):资源的表现形式可以是多种多样的,比如JSON、XML、HTML等。客户端通过资源的表现形式与服务器进行交互。

  3. 状态转移(State Transfer):RESTful架构强调通过HTTP协议的各种方法来对资源进行操作,包括GET、POST、PUT、DELETE等,这些方法对应着资源的不同操作。

  4. 无状态(Stateless):服务器不会保存客户端的状态信息,每个请求都应该包含足够的信息使得服务器可以理解请求。这样的设计使得系统更容易扩展和更加可靠。

  5. 统一接口(Uniform Interface):RESTful架构提倡使用统一的接口进行通信,使得不同的客户端和服务器可以相互通信。这种设计方式降低了系统的耦合性,提高了系统的可维护性和可扩展性。

通过遵循RESTful架构风格,开发人员可以设计出简单、灵活、高效的网络应用程序,使得不同系统之间的通信更加简单和可靠。

Flask-RESTful的基本使用

Flask-RESTful是一个基于Flask框架的扩展,用于构建RESTful API。它简化了在Flask应用程序中创建RESTful API的过程,提供了一种简单且优雅的方式来定义资源和处理请求。以下是使用Flask-RESTful的一般步骤:

安装Flask-RESTful:首先,你需要安装Flask-RESTful。你可以通过pip来安装它:

pip install flask-restful

基本使用

from flask import Flask, url_for
from flask_restful import Api, Resource# 创建Flask应用程序
app = Flask(__name__)
# 创建API对象
api = Api(app)# 创建一个简单的资源类
class HelloWorld(Resource):  # 需要继承Resource类# 定义GET方法处理器def get(self):return {'message': '返回用户数据'}  # 返回JSON响应# 定义POST方法处理器def post(self):return {'message': '添加新用户返回信息'}  # 返回JSON响应class TestView(Resource):def get(self):return {'message': 'test for empty endpoint'}# 将资源添加到API,并指定URL路径
api.add_resource(HelloWorld, '/user', '/user2', endpoint='user')  # 将HelloWorld资源添加到根路径
api.add_resource(TestView, '/test')  # 将HelloWorld资源添加到根路径
# 上下文测试
with app.test_request_context():print(url_for("user"))  # 打印/user 当设置多个地址,只会返回第一个地址print(url_for("testview"))  # 打印/test 如果没有设置endpoint,使用类的小写则是默认方案if __name__ == '__main__':# 运行Flask应用程序app.run(debug=True)
  • 导入模块:Flask用于创建Web应用程序,ApiResource是Flask-RESTful提供的用于构建RESTful API的类。

  • 创建Api对象,用于管理API的资源。

  • 定义资源类HelloWorld,继承自Resource类。在这个类中,定义get方法作为处理GET请求的处理器,定义post方法作为处理POST请求的处理器。

  • 使用api.add_resource()方法将HelloWorld资源添加到API中,并指定了URL路径为'/'user,这里可以指定多个路径,都可以使用这个类的逻辑。

还可以设置endpoint参数,用来作为标识,当没有设置的时候,默认标识是类名的全小写,当使用url_for的时候,如果设置了多个路径,只会返回第一个路径。

使用 reqparse 解析数据

在 Flask-RESTful 中,reqparse 是一个用于解析和验证请求参数的实用工具。它可以简化处理客户端发送的数据,确保数据的有效性和完整性。

reqparse 允许我们定义期望的请求参数,并提供类型验证和错误处理。下面是一个示例:

from flask import Flask
from flask_restful import Api, Resource, reqparse# 创建一个基本的 Flask 应用并添加 Flask-RESTful 支持
app = Flask(__name__)
api = Api(app)# 定义资源
class User(Resource):def post(self):parser = reqparse.RequestParser()# 定义期望的参数parser.add_argument('name', type=str, required=True, help='Name cannot be blank!')parser.add_argument('age', type=int, help='Age of the user')parser.add_argument('gender', type=str, choices=('male', 'female'), help='Gender must be either "male" or "female"')# 解析参数args = parser.parse_args()return {'message': f"Hello, {args['name']}! You are {args.get('age', 'of unknown age')} years old and your gender is {args.get('gender', 'unspecified')}."}, 201# 添加资源到API
api.add_resource(User, '/user')if __name__ == '__main__':app.run(debug=True)

在这个示例中,我们定义了一个 User 资源,并在 post 方法中使用 reqparse 来解析请求体中的 nameagegender 参数。

参数验证
reqparse 可以对参数进行验证和处理。例如,可以设置参数类型、默认值、必需性等:

parser.add_argument('name', type=str, required=True, help='Name cannot be blank!')
parser.add_argument('age', type=int, help='Age of the user', default=18)
parser.add_argument('gender', type=str, choices=('male', 'female'), location='form', help='Gender must be either "male" or "female"')
  • type:参数的数据类型。如果类型不匹配,将返回错误。
  • required:是否为必需参数。如果未提供该参数,将返回错误。
  • help:当验证失败时返回的错误信息。
  • choices:参数的可选值列表。如果参数的值不在列表中,将返回错误。
  • location:指定从哪里获取参数(例如:jsonargsform)。

parser.add_argument参数介绍

参数类型默认值说明示例
namestr参数名称parser.add_argument('name')
typecallablestr参数的数据类型,传入一个可调用对象(如 int, str, float)用于类型转换parser.add_argument('age', type=int)
requiredboolFalse是否为必需参数,如果未提供则返回错误parser.add_argument('name', required=True)
helpstr当参数验证失败时返回的错误信息parser.add_argument('name', required=True, help='Name cannot be blank!')
default任意类型参数的默认值,如果请求中未提供则使用此值parser.add_argument('age', type=int, default=18)
choiceslist参数的可选值列表,如果值不在列表中则返回错误parser.add_argument('gender', type=str, choices=['male', 'female'])
locationstrlist指定从请求的哪个部分获取参数,选项包括 'json', 'args', 'form', 'headers', 'cookies', 'files'parser.add_argument('name', location='json')
actionstr'store'指定对参数值执行的操作,如 'store', 'store_const', 'append', 'append_const', 'count'parser.add_argument('tags', action='append')
deststr参数名称参数存储在 args 对象中的属性名称parser.add_argument('username', dest='user_name')
trimboolFalse是否自动去除参数值两端的空格parser.add_argument('name', type=str, trim=True)
case_sensitiveboolTrue是否区分参数值的大小写parser.add_argument('gender', type=str, choices=['male', 'female'], case_sensitive=False)

完整示例
为了更好地理解上述参数的用法,以下是一个综合示例,展示了如何使用 reqparse 来解析和验证请求参数:

from flask import Flask
from flask_restful import Api, Resource, reqparseapp = Flask(__name__)
api = Api(app)class User(Resource):def post(self):parser = reqparse.RequestParser()parser.add_argument('name', type=str, required=True, help='Name cannot be blank!', location='form', trim=True)parser.add_argument('age', type=int, help='Age of the user', default=18, location='form')parser.add_argument('gender', type=str, choices=['male', 'female'], help='Gender must be either "male" or "female"', location='form', case_sensitive=False)parser.add_argument('tags', action='append', help='Tags for the user', location='form')args = parser.parse_args()return {'message': f"Hello, {args['name']}! You are {args.get('age', 'of unknown age')} years old, your gender is {args.get('gender', 'unspecified')}, and your tags are {args.get('tags', [])}."}, 201# 添加资源到API
api.add_resource(User, '/user')if __name__ == '__main__':app.run(debug=True)

数据样例

下面是一些使用 curl 命令和 JSON 数据格式的示例请求,这些示例演示了如何向 /user 端点发送数据,以便触发 User 资源的 post 方法。

示例 1:所有参数都提供且正确

curl -X POST http://127.0.0.1:5000/user -H "Content-Type: application/x-www-form-urlencoded" -d "name=John&age=30&gender=male&tags=developer&tags=blogger"

预期响应:

{"message": "Hello, John! You are 30 years old, your gender is male, and your tags are ['developer', 'blogger']."
}

示例 2:缺少可选参数 agetags

curl -X POST http://127.0.0.1:5000/user -H "Content-Type: application/x-www-form-urlencoded" -d "name=Jane&gender=female"

预期响应:

{"message": "Hello, Jane! You are 18 years old, your gender is female, and your tags are []."
}

示例 3:缺少必需参数 name

curl -X POST http://127.0.0.1:5000/user -H "Content-Type: application/x-www-form-urlencoded" -d "age=25&gender=male"

预期响应:

{"message": {"name": "Name cannot be blank!"}
}

示例 4:参数 gender 的值不在指定选项中

curl -X POST http://127.0.0.1:5000/user -H "Content-Type: application/x-www-form-urlencoded" -d "name=Alex&age=40&gender=other"

预期响应:

{"message": {"gender": "Gender must be either \"male\" or \"female\""}
}

示例 5:发送 JSON 格式的数据

curl -X POST http://127.0.0.1:5000/user -H "Content-Type: application/json" -d '{"name": "Emma", "age": 22, "gender": "female", "tags": ["artist", "musician"]}'

预期响应:

{"message": "Hello, Emma! You are 22 years old, your gender is female, and your tags are ['artist', 'musician']."
}

示例 6:参数值含有空格,启用 trim 功能

curl -X POST http://127.0.0.1:5000/user -H "Content-Type: application/x-www-form-urlencoded" -d "name= Alice &age=27&gender=female"

预期响应:

{"message": "Hello, Alice! You are 27 years old, your gender is female, and your tags are []."
}

使用 marshal_with 规范化 返回值

它允许你定义一个响应模板,将返回的对象映射到这个模板上,确保返回的数据结构符合你的预期。

创建一个简单的 Flask 应用并使用 Flask-RESTful 创建 API 接口:

from flask import Flask, request
from flask_restful import Api, Resource, fields, marshal_withapp = Flask(__name__)
api = Api(app)user_fields = {'code': fields.Integer(default=200),'message': fields.String
}class UserResponse:def __init__(self, message):self.message = messageclass UserResource(Resource):@marshal_with(user_fields)def post(self):user_response = UserResponse(message=request.values.get('message'))return user_responseapi.add_resource(UserResource, '/user')if __name__ == '__main__':app.run(debug=True)

在这个案例中,当给http://127.0.0.1:5000/user发送数据之后,即使没有给返回对象添加code的值,使用规范化参数之后,其自动添加然后返回数据。
在这里插入图片描述

fields参数设置

Flask-RESTful 是一个扩展 Flask 的库,它能够方便地构建基于 REST 的 API。这个库简化了开发 RESTful 服务所需的一些常见任务,比如 URL 路由和请求处理。fields 模块在 Flask-RESTful 中用于定义资源的序列化规则,即如何将 Python 对象转换为 JSON 格式进行响应。

fields 模块

fields 模块提供了一系列字段类型和辅助工具,帮助你指定如何序列化你的资源字段。常用的字段类型包括:

  • fields.String
  • fields.Integer
  • fields.Float
  • fields.Boolean
  • fields.List
  • fields.Nested

fields 参数详解

下面是一些常见的 fields 参数及其用法。

fields.String

用于表示字符串类型的字段。

from flask_restful import fieldsresource_fields = {'name': fields.String,'description': fields.String(default='No description')
}

参数

  • attribute: 指定对象中的哪个属性用于序列化。如果不提供,默认使用字段名。
  • default: 如果对象中没有该字段,使用默认值。
fields.Integer

用于表示整数类型的字段。

resource_fields = {'id': fields.Integer,'age': fields.Integer(default=0)
}

参数

  • attribute: 指定对象中的哪个属性用于序列化。如果不提供,默认使用字段名。
  • default: 如果对象中没有该字段,使用默认值。
fields.Float

用于表示浮点数类型的字段。

resource_fields = {'price': fields.Float,'rating': fields.Float(default=0.0)
}

参数

  • attribute: 指定对象中的哪个属性用于序列化。如果不提供,默认使用字段名。
  • default: 如果对象中没有该字段,使用默认值。
fields.Boolean

用于表示布尔类型的字段。

resource_fields = {'is_active': fields.Boolean,'is_verified': fields.Boolean(default=False)
}

参数

  • attribute: 指定对象中的哪个属性用于序列化。如果不提供,默认使用字段名。
  • default: 如果对象中没有该字段,使用默认值。
fields.List

用于表示一个列表。需要指定列表中的元素类型。

resource_fields = {'tags': fields.List(fields.String)
}

参数

  • cls_or_instance: 列表中元素的字段类型。
fields.Nested

用于表示嵌套的复杂对象。

nested_fields = {'street': fields.String,'city': fields.String,'state': fields.String,'zipcode': fields.String
}resource_fields = {'name': fields.String,'address': fields.Nested(nested_fields)
}

参数

  • model: 嵌套对象的字段定义。
  • allow_null: 是否允许嵌套对象为空。

使用示例

定义一个资源类并使用 marshal_with 装饰器应用字段规则:

from flask import Flask
from flask_restful import Api, Resource, fields, marshal_withapp = Flask(__name__)
api = Api(app)resource_fields = {'id': fields.Integer,'name': fields.String,'age': fields.Integer,'address': fields.Nested({'street': fields.String,'city': fields.String,'state': fields.String,'zipcode': fields.String})
}class UserResource(Resource):@marshal_with(resource_fields)def get(self):user = {'id': 1,'name': 'John Doe','age': 30,'address': {'street': '123 Elm St','city': 'Springfield','state': 'IL','zipcode': '62701'}}return userapi.add_resource(UserResource, '/user')if __name__ == '__main__':app.run(debug=True)

在这个示例中,marshal_with 装饰器根据 resource_fields 的定义将 UserResource 的返回值序列化为 JSON 格式。

RESTful和蓝图结合使用

在 Flask 中,RESTful 和蓝图(Blueprints)的结合使用能够使应用程序的结构更加清晰和模块化。

from flask import Flask, Blueprint
from flask_restful import Api, Resource, fields, marshal_with# 创建 Flask 应用
app = Flask(__name__)# 创建蓝图
api_bp = Blueprint('api', __name__)
api = Api(api_bp)# 定义资源字段
resource_fields = {'id': fields.Integer,'name': fields.String,'age': fields.Integer,
}# 定义资源类
class UserResource(Resource):@marshal_with(resource_fields)def get(self, user_id):user = {'id': user_id,'name': 'John Doe','age': 30}return user# 将资源添加到蓝图的 API 中
api.add_resource(UserResource, '/user/<int:user_id>')# 注册蓝图
app.register_blueprint(api_bp, url_prefix='/api')# 运行应用
if __name__ == '__main__':app.run(debug=True)

创建蓝图和 API:

  • Blueprint('api', __name__) 创建一个名为 api 的蓝图。
  • Api(api_bp) 将蓝图传递给 Flask-RESTful 的 Api 对象,使其能够处理蓝图中的路由。

定义资源和字段:

  • 使用 fields 模块定义资源的序列化规则。
  • 创建一个继承自 Resource 的资源类 UserResource,并使用 marshal_with 装饰器将返回的 Python 对象序列化为 JSON。

添加资源到 API:

  • api.add_resource(UserResource, '/user/<int:user_id>')UserResource 添加到 API 中,指定它的访问路径。

注册蓝图:

  • app.register_blueprint(api_bp, url_prefix='/api') 将蓝图注册到 Flask 应用,并设置 URL 前缀为 /api,使得所有蓝图中的路由都以 /api 开头。

和RESTful的基本使用相比,其实就是将api对象的创建进行修改,把原本的app对象换成蓝图对象

api = Api(app) # 基本
api = Api(api_bp) # 使用蓝图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/702862.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue.js 详细介绍

文章目录 一、Vue.js 简介1.1 什么是 Vue.js&#xff1f;1.2 Vue.js 的特点 二、快速上手 Vue.js2.1 安装 Vue.js使用 CDN使用 npm 或 yarn 2.2 创建一个 Vue 实例2.3 Vue.js 项目结构 三、Vue.js 核心概念3.1 数据绑定3.2 指令&#xff08;Directives&#xff09;3.3 组件&…

自由职业是种怎样的体验?普通人如何成为一名自由职业者?

自由职业在哪都能办公自由职业在哪都要办公。 放弃幻想&#xff0c;没有不辛苦的工作&#xff0c;5年经验后端开发程序员&#xff0c;已经从事自由职业1年半&#xff0c;今天就来客观分享一下自由职业的利与弊。 时间自由&#xff0c;减少中间商赚差价 自由职业最让人羡慕的就…

移动烽火HG光猫超密破解

1、查找mac地址 cmd 运行 arp -a 192.168.1.1 2、开启telnet功能 浏览器输入 http://192.168.1.1/cgi-bin/telnetenable.cgi?telnetenable1&key3086F178B450 注释&#xff1a; telnetenable1 开启telnet功能 key 是第一步查询的mac地址&#xff0c;去掉横线、小写…

GPT4o速测:约0.5秒延迟的多模态能力

文章目录 1. 测评2. IntroReference 没有剪辑&#xff0c;约0.5秒延迟的多模态能力。 1. 测评 推理速度异常快&#xff0c;比之前快了大概两三倍&#xff0c;对产品端来说是个很好的事情&#xff0c;想用gpt4级别性能终于可以少讨论几句时延影响用户体验了模型指令遵从能力变强…

【Java】/*数组的定义与使用*/

目录 一、数组的定义 1.1 为什么要使用数组 1.2 什么是数组 1.3 数组的初始化 1.3.1 动态初始化 1.3.2 静态初始化 1.2.3 注意事项 三、遍历数组 3.1 用循环的方式遍历数组 3.2 用 for each 的方式遍历数组 3.3 用 Arrays.toString 的方式遍历数组 3.4 一些其他的…

FOSS全闪对象存储--与AI/ML相向而行

行业解读需求剖析 目前&#xff0c;随着AI/ML技术得到了快速的发展及应用&#xff0c;AI/ML系统对底层高速数据访问的需求也日趋强烈&#xff0c;虽然当前业界有多种解决方案&#xff0c;但都存在一些成本或性能方面的挑战&#xff0c;就目前常用的文件存储系统来说&#xff0…

PDF编辑阅读器PDF Expert for Mac v3.10.1中文激活版

PDF Expert for Mac是一款易于使用的 PDF 编辑器和注释器&#xff0c;专为 Mac 设备设计。它允许用户轻松查看、编辑、签名、注释和共享 PDF。该软件使用户能够向他们的 PDF 添加文本、图像、链接和形状&#xff0c;突出显示和标记文本&#xff0c;填写表格以及签署数字文档。它…

java聊天室项目小结

实现了群管理&#xff0c;发起群聊功能&#xff0c;可以解散群&#xff0c;退出群里&#xff0c;群主修改群基本信息&#xff0c;邀请好友进群功能 邀请好友&#xff0c;只会显示没被邀请的好友 今天完成申请入群&#xff0c;群踢人&#xff0c;设置管理员等操作

软考-下午题-试题一

1、概念 2、答题技巧和规范 问题1、2&#xff1a;直接看 格式&#xff1a; 问题3&#xff1a; 格式&#xff1a; 3、例题 eg2&#xff1a;可以以后写完问题4之后&#xff0c;把问题3补充完整 问题4&#xff1a; 问题4 官方解释&#xff1a; 问题4&#xff08;3‘&#xff09; 2…

批量下载huggingface的仓库全部权重文件

下载huggingface的仓库全部权重文件 配置和下载git-lfs **ubuntu:**sudo apt-get install git-lfs 其他&#xff1a; 下载git-lfs Releases git-lfs/git-lfs (github.com) 配置&#xff1a; export PATH$PATH://home/software/lfs/git-lfs-3.5.1/ # 其中目录为你文件夹的目…

【软件的安装与基本设置】AD21软件的PCB规则设置

在绘制PCB之前&#xff0c;要进行规则的创建&#xff0c;因为在绘制PCB的过程中&#xff0c;难免会出现很多错误&#xff0c;所以需要先对绘制PCB创建规则&#xff0c;即所有的打孔&#xff0c;走线&#xff0c;铺铜都要基于电气性能规则去设计&#xff0c;等到后期&#xff0c…

LeetCode算法题:49. 字母异位词分组(Java)

给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "nat", …