【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.xdnf.cn/news/1423965.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

tensorflow实现二分类

# 导入所需库和模块 from tensorflow.keras.layers import Dense, Input, Activation # 导入神经网络层和激活函数模块 from tensorflow.keras.models import Sequential # 导入Keras的Sequential模型 import pandas as pd # 导入Pandas库用于数据处理 import numpy as np …

如何部署TDE透明加密实现数据库免改造加密存储

安当TDE&#xff08;透明数据加密&#xff09;实现数据库加密的步骤主要包括以下几个部分&#xff1a; 准备安装环境&#xff1a;确保操作系统和数据库环境已经安装并配置好&#xff0c;同时确保具有足够的权限来安装和配置TDE透明加密组件。下载安装包&#xff1a;从官方网站…

2024年5月18日(星期六)骑行香杆箐

2024年5月18日 (星期六&#xff09;骑行香杆箐&#xff0c;早8:30到9:00&#xff0c;郊野公园西门集合&#xff0c;9:30准时出发【因迟到者&#xff0c;骑行速度快者&#xff0c;可自行追赶偶遇。】 偶遇地点:郊野公园西门集合 &#xff0c;家住东&#xff0c;西&#xff0c;南…

通过视频生成实现基于物理的3D对象交互——PhysDreamer

随着虚拟现实(VR)和增强现实(AR)技术的飞速发展&#xff0c;用户对于虚拟体验的真实性提出了更高的要求。在这样的背景下&#xff0c;PhysDreamer应运而生&#xff0c;它是一项创新的技术&#xff0c;能够为静态3D对象赋予逼真的物理交互动态&#xff0c;极大地丰富了虚拟环境的…

使用DBeaver的第2天-使用sql导入数据

使用sql导入数据这块我会仔细的说一下 首先位置一定要放在库上&#xff08;实例&#xff09;&#xff0c;放在表上可不好使用哦 然后点击工具-再点击执行脚本 这样就执行成功了 但是如果你执行失败了&#xff0c;多半可能是因为本地没有部署mysql&#xff0c;记住只有本地有…

5G技术相关部分图解

1、面向5G商用网络的全系列解决方案 面向5G商用网络的全系列解决方案涵盖了从核心网到接入网的各个方面&#xff0c;确保网络的高性能、高可靠性和高安全性 2、2\3\4\5G带宽图解 G带宽的提升将推动许多新型应用的发展&#xff0c;并提供更快速、更可靠的移动通信体验。然而…

【运维自动化-配置平台】如何自动应用主机属性

主要用于配置主机属性的自动应用。当主机发生模块转移或模块新加入主机时&#xff0c;会根据目标模块配置的策略自动触发修改主机属性&#xff0c;比如主机负责人、主机状态。主机属性自动应用顾名思义是应用到主机上&#xff0c;而主机是必须在模块下的&#xff0c;所以有两种…

代码随想录训练营Day31:动态规划3:0-1背包

1.0-1背包基础 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 1.1动态规划五部曲 确定dp数组以及下标的含义&#xff1a;dp[i][j] 表示…

【计算机网络】HTTP协议详解实战抓包分析教程

文章目录 1.HTTP简介2.HTTP报文的结构3.HTTP协议中空行的作用4.uri和url的区别5.HTTP请求5.1 HTTP请求方法5.2 HTTP请求报头 6.HTTP响应6.1 状态码 7.HTTP位于应用层(基于TCP)8.非持久和持久连接8.1 非持久连接8.2 持久连接 1.HTTP简介 HTTP&#xff08;Hypertext Transfer Pr…

爬虫入门经典(七) | 采集淘宝电场相关信息

大家好&#xff0c;我是不温卜火&#xff0c;昵称来源于成语—不温不火&#xff0c;本意是希望自己性情温和。 PS&#xff1a;由于现在越来越多的人未经本人同意直接爬取博主本人文章&#xff0c;博主在此特别声明&#xff1a;未经本人允许&#xff0c;禁止转载&#xff01;&a…

BakedSDF: Meshing Neural SDFs for Real-Time View Synthesis 论文阅读

&#xff08;水一篇博客&#xff09; 项目主页 BakedSDF: Meshing Neural SDFs for Real-Time View Synthesis 作者介绍 是 Mildenhall 和 Barron 参与的工作&#xff08;都是谷歌的&#xff09;&#xff0c;同时一作是 Lipman 的学生&#xff0c;VolSDF 的一作。本文引用…

VMware17.5与Ubuntu22.04虚拟机环境搭建

VMware17.5安装教程也有参考此链接 简介 Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的Unix工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设…

【面试必看】MySQL部分

MySQL 1. 基础 1. 什么是关系型数据库&#xff1f; 一种建立在关系模型的基础上的数据库。关系模型表明了数据库中所存储的数据之间的联系&#xff08;一对一、一对多、多对多&#xff09;。各种表中&#xff08;比如用户表&#xff09;&#xff0c;表中的每一行就存放着一条…

ARM基于DWT实现硬件延时(GD32)

软件延时的缺点 软件延时的精度差&#xff0c;受系统主频影响&#xff0c;调教困难 硬件延时 DWT数据跟踪监视点单元硬件延时 硬件延时实现代码 delay.c #include <stdint.h> #include "gd32f30x.h"/** *****************************************************…

InfiniGate自研网关实现五

17.核心通信组件管理和处理服务映射 引入模块api-gateway-core 到 api-gateway-assist 中进行创建和使用&#xff0c;并拉取自注册中心的映射信息注册到本地的网关通信组件中。 第17节是在第15节的基础上继续完善服务发现的相关功能&#xff0c;把从注册中心拉取的网关映射信…

Qt qt5.3集成mqtt模块

参考 【Qt官方MQTT库的使用&#xff0c;附一个MqttClient例子】 - 叶小鹏 - 博客园 (cnblogs.com)MQTT&#xff1a;windows最简单搭建mqtt服务端及本地客户端测试_emqx-windows-4.3.6-CSDN博客MQTTX 下载 编译 我从Github下载的是Release v5.12.5 qt/qtmqtt (github.com)版…

达梦(DM) SQL基础操作

达梦DM SQL基础操作 用户与模式SQL基础操作查看表结构基础查询语句 在进行DM数据库SQL开发之前&#xff0c;首先需要了解一下DM数据库用户与模式的关系&#xff0c;因为这将直接影响到你后续对DM数据库的操作。那么DM数据库用户与模式的关系怎么理解呢&#xff1f; 用户与模式 …

【Linux系统编程】基本指令(二)

目录 1、mv指令 2、cat指令 输出重定向 ​编辑 追加重定向 输入重定向 3、more指令 4、less指令 5、head指令 6、tail指令 与时间相关的指令 7、date指令 8、cal指令 9、find指令 10、grep指令 11、zip/unzip指令 1、mv指令 mv文件是用来对文件或目录进行重命名…

vue3专栏项目 -- 五、权限管理(上)

一、登录部分 1、第一部分&#xff1a;获取token 前面我们主要是在获取数据上下功夫&#xff0c;到目前为止我们已经能获取首页和详情页的数据了&#xff0c;现在我们将数据转移到权限管理上来&#xff0c;也就是说我们要处理用户登录、注册等一系列的行为&#xff0c;在这部…

##20 实现图像风格迁移:使用PyTorch深入学习的艺术之旅

文章目录 前言项目概述准备阶段图像处理模型选择风格和内容特征提取风格迁移算法优化过程结果展示完整代码与实验项目结论参考文献 前言 图像风格迁移是一种使一幅图像呈现另一幅画作风格的技术&#xff0c;通过深度学习&#xff0c;我们能够捕捉到内容图像的结构信息和风格图…