网站建设谈单技巧,WordPress推送百家号,生活中好的设计产品,建设跨境电商网站我这几天上手体验 FastAPI#xff0c;感受到这个框架易用和方便。之前也使用过 Python 中的 Django 和 Flask 作为项目的框架。Django 说实话上手也方便#xff0c;但是学习起来有点重量级框架的感觉#xff0c;FastAPI 带给我的直观体验还是很轻便的#xff0c;本文就会着… 我这几天上手体验 FastAPI感受到这个框架易用和方便。之前也使用过 Python 中的 Django 和 Flask 作为项目的框架。Django 说实话上手也方便但是学习起来有点重量级框架的感觉FastAPI 带给我的直观体验还是很轻便的本文就会着重介绍 FastAPI 和 Flask 的区别。 Python 是最流行的编程语言之一。从脚本到 API 开发再到机器学习Python 都有着它自己的足迹。因为 Python 注重开发者的体验和其所能提供的大量工具而大受欢迎。网络框架 Flask 就是这样一个工具它在机器学习社区中很受欢迎。它也被广泛用于 API开发。但是有一个新的框架正在崛起 FastAPI。
与 Flask 不同FastAPI 是一个 ASGIAsynchronous Server Gateway Interface 异步服务器网关接口框架。与 Go 和 NodeJS 一样FastAPI 是最快的基于 Python 的 Web 框架之一。
本文针对那些有兴趣从 Flask 转移到 FastAPI 的人比较和对比了 Flask 和 FastAPI 的常见模式。 文章目录 实战项目系列FastAPI vs Flask开始安装Hello World 应用 配置路由, 模板和视图HTTP 方法URL 参数查询参数模板静态文件异步任务依赖注入数据校验序列化和反序列化中间件模块化 其他特点自动文档管理应用身份认证CORS 测试部署生产服务器Docker 总结官方文档其他资源 实战项目系列
实战基于PythonFlaskMySQL的豆瓣电影可视化系统实战搭建基于 PythonFlaskMySQL 的学生培养计划管理系统附源码实战一款基于 Pythonflask 的态势感知系统附完整源码)实战基于 Python 的 Flask 框架开发的在线电影网站系统附完整源码实战基于 Echarts Python Flask 动态实时大屏轻松可以实现实战基于 PythonDjango 构建智能互动拍照系统实战基于 PythonFlaskSQLite 的网易云音乐评论情感分析系统实战基于 Python 和Surprise库新手轻松搭建推荐系统实战基于 PythonDjangoMySQL 数据库的租房数据可视化系统
FastAPI vs Flask FastAPI 的构建考虑了以下三个主要问题 速度 开发者经验 开放标准
你可以把 FastAPI 看作是把 Starlette、Pydantic、OpenAPI 和 JSON Schema 粘合在一起的胶水。 本质上说FastAPI 使用 Pydantic 进行数据验证并使用 Starlette 作为工具使其与 Flask 相比快得惊人具有与 Node 或 Go 中的高速 Web APIs 相同的性能。 Starlette Uvicorn 提供异步请求能力这是 Flask 所缺乏的。 有了 Pydantic 以及类型提示你就可以得到一个具有自动完成功能的良好的编辑体验。你还可以得到数据验证、序列化和反序列化用于构建一个 API以及自动化文档通过 JSON Schema 和 OpenAPI 。
也就是说Flask 的使用更为广泛所以它经过了实战检验并且有更大的社区支持它。由于这两个框架都是用来扩展的Flask 显然是赢家因为它有庞大的插件生态系统。
建议 如果你对上述三个问题有共鸣厌倦了 Flask 扩展时的大量选择希望利用异步请求或者只是想建立一个 RESTful API请使用 FastAPI。 如果你对 FastAPI 的成熟度不满意需要用服务器端模板构建一个全栈应用或者离不开一些社区维护的 Flask 扩展就可以使用 Flask。
开始 安装
与任何其他 Python 包一样安装非常简单。
Flask
pip install flask# or
poetry add flask
pipenv install flask
conda install flaskFastAPI
pip install fastapi uvicorn# or
poetry add fastapi uvicorn
pipenv install fastapi uvicorn
conda install fastapi uvicorn -c conda-forge与 Flask 不同FastAPI 没有内置的开发服务器因此需要像 Uvicorn 或 Daphne 这样的 ASGI 服务器。
“Hello World” 应用
Flask
# flask_code.pyfrom flask import Flaskapp Flask(__name__)app.route(/)
def home():return {Hello: World}if __name__ __main__:app.run()FastAPI
# fastapi_code.pyimport uvicorn
from fastapi import FastAPIapp FastAPI()app.get(/)
def home():return {Hello: World}if __name__ __main__:uvicorn.run(fastapi_code:app)像 reloadTrue 这样的参数可以被传递到 uvicorn.run() 中以实现开发时的热重载。
或者您可以直接从终端启动服务器
uvicorn run fastapi_code:app热加载模式
uvicorn run fastapi_code:app --reload配置 Flask 和 FastAPI 都提供了许多选项来处理不同环境的不同配置。两者都支持以下模式 环境变量 配置文件 实例文件夹 类和继承
有关更多信息请参阅其各自的文档 Flask: https://flask.palletsprojects.com/en/2.0.x/config/ FastAPI:https://fastapi.tiangolo.com/advanced/settings/
Flask
import os
from flask import Flaskclass Config(object):MESSAGE os.environ.get(MESSAGE)app Flask(__name__)
app.config.from_object(Config)app.route(/settings)
def get_settings():return { message: app.config[MESSAGE] }if __name__ __main__:app.run()现在在你运行服务器之前设置适当的环境变量
export MESSAGEhello, worldFastAPI
import uvicorn
from fastapi import FastAPI
from pydantic import BaseSettingsclass Settings(BaseSettings):message: strsettings Settings()
app FastAPI()app.get(/settings)
def get_settings():return { message: settings.message }if __name__ __main__:uvicorn.run(fastapi_code:app)同样在运行服务器之前设置适当的环境变量
export MESSAGEhello, world路由, 模板和视图 HTTP 方法
Flask
from flask import requestapp.route(/, methods[GET, POST])
def home():# handle POSTif request.method POST:return {Hello: POST}# handle GETreturn {Hello: GET}FastAPI
app.get(/)
def home():return {Hello: GET}app.post(/)
def home_post():return {Hello: POST}FastAPI 为每个方法提供单独的装饰器
app.get(/)
app.post(/)
app.delete(/)
app.patch(/)URL 参数
通过 URL如 /employee/1 传递信息以管理状态
Flask
app.route(/employee/int:id)
def home():return {id: id}FastAPI
app.get(/employee/{id})
def home(id: int):return {id: id}URL参数的指定类似于一个 f-string 表达式。此外你还可以利用类型提示。这里我们在运行时告诉 Pydantic id 是 int 类型的。在开发中这也可以帮助完成更好的代码完成度。
查询参数
与 URL 参数一样查询参数如 /employee?departmentsales 也可用于管理状态通常用于过滤或排序
Flask
from flask import requestapp.route(/employee)
def home():department request.args.get(department)return {department: department}FastAPI
app.get(/employee)
def home(department: str):return {department: department}模板
Flask
from flask import render_templateapp.route(/)
def home():return render_template(index.html)默认情况下Flask会在 templates 文件夹中寻找模板。
FastAPI
你需要安装 Jinja
pip install jinja2实现
from fastapi import Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponseapp FastAPI()templates Jinja2Templates(directorytemplates)app.get(/, response_classHTMLResponse)
def home(request: Request):return templates.TemplateResponse(index.html, {request: request})对于 FastAPI你需要明确地定义 模板 文件夹。然后对于每个响应需要提供请求上下文。
静态文件
Flask
默认情况下Flask 从“static”文件夹中提供静态文件。
FastAPI
在 FastAPI 中需要为静态文件挂载一个文件夹
from fastapi.staticfiles import StaticFilesapp FastAPI()app.mount(/static, StaticFiles(directorystatic), namestatic)异步任务
Flask
从 Flask 2.0 开始您可以使用 async/await 创建异步路由处理程序
app.route(/)
async def home():result await some_async_task()return result有关 Flask 中异步视图的更多信息请查看 Flask 2.0 中的异步一文。 Flask 中的异步也可以通过使用线程并发或多处理并行或 Celery 或 RQ 等工具来实现 Asynchronous Tasks with Flask and Celeryhttps://testdriven.io/blog/flask-and-celery/ Asynchronous Tasks with Flask and Redis Queuehttps://testdriven.io/blog/asynchronous-tasks-with-flask-and-redis-queue/
FastAPI
由于 FastAPI 对 asyncio 的原生支持它极大地简化了异步任务。要使用的话只需在视图函数中添加 async 关键字
app.get(/)
async def home():result await some_async_task()return resultFastAPI 还具有后台任务功能您可以使用它来定义返回响应后要运行的后台任务。这对于不需要在发送回响应之前完成的操作很有用。
from fastapi import BackgroundTasksdef process_file(filename: str):# process file :: takes minimum 3 secs (just an example)passapp.post(/upload/{filename})
async def upload_and_process(filename: str, background_tasks: BackgroundTasks):background_tasks.add_task(process_file, filename)return {message: processing file}在这里响应将被即时发送而不会让用户等待文件处理完成。
当你需要进行繁重的后台计算时或者你需要一个任务队列来管理任务(tasks)和工作者(workers)时你可能想使用Celery 而不是 BackgroundTasks。更多内容请参考 FastAPI 和 Celery 的异步任务https://testdriven.io/blog/fastapi-and-celery/
依赖注入
Flask
虽然你可以实现自己的依赖注入解决方案但 Flask 默认没有真正的一流支持。相反你需要使用一个外部包如 flask-injector。
FastAPI
另一方面FastAPI 具有处理依赖注入的强大解决方案。
例如
from databases import Database
from fastapi import Depends
from starlette.requests import Requestfrom db_helpers import get_all_data
def get_db(request: Request):return request.app.state._dbapp.get(/data)
def get_data(db: Database Depends(get_db)):return get_all_data(db)因此get_db 将获取对在应用程序的启动事件处理程序中创建的数据库连接的引用。 Depends 然后用于向 FastAPI 指示路由“依赖于” get_db。因此它应该在路由处理程序中的代码之前执行并且结果应该“注入”到路由本身。
数据校验
Flask
Flask 没有任何内部数据验证支持。您可以使用功能强大的 Pydantic 包通过 Flask-Pydantic 进行数据验证。
FastAPI
FastAPI 如此强大的原因之一是它支持 Pydantic。
from pydantic import BaseModelapp FastAPI()class Request(BaseModel):username: strpassword: strapp.post(/login)
async def login(req: Request):if req.username testdriven.io and req.password testdriven.io:return {message: success}return {message: Authentication Failed}在这里我们接受一个模型 Request 的输入。该 payload 必须包含一个用户名和密码。
# correct payload format
✗ curl -X POST localhost:8000/login \--header Content-Type: application/json \--data-raw {username: testdriven.io,password:testdriven.io}{message:success}# incorrect payload format
✗ curl -X POST localhost:8000/login \--header Content-Type: application/json \--data-raw {username: testdriven.io,passwords:testdriven.io}{detail:[{loc:[body,password],msg:field required,type:value_error.missing}]}注意到这个请求。我们把密码 passwords 作为一个键而不是 password 传递进去。Pydantic 模型会自动告诉用户password 字段是缺失的。
序列化和反序列化
Flask
最简单的序列化方法是使用 jsonify
from flask import jsonify
from data import get_data_as_dictapp.route(/)
def send_data():return jsonify(get_data_as_dict)对于复杂的对象Flask 开发者经常使用 Flask-Marshmallow
FastAPI
FastAPI 自动序列化任何返回的字典 dict 。对于更复杂和结构化的数据使用 Pydantic
from pydantic import BaseModelapp FastAPI()class Request(BaseModel):username: stremail: strpassword: strclass Response(BaseModel):username: stremail: strapp.post(/login, response_modelResponse)
async def login(req: Request):if req.username testdriven.io and req.password testdriven.io:return reqreturn {message: Authentication Failed}在这里我们添加了一个包含三个输入的 Request 模型用户名、电子邮件和密码。我们还定义了一个仅包含用户名和电子邮件的 Response 模型。输入 Request 模型处理反序列化而输出 Response 模型处理对象序列化。然后通过 response_model 参数将响应模型传递给装饰器。
现在如果我们将请求本身作为响应返回Pydantic 将省略 password 因为我们定义的响应模型不包含密码字段。
例如
# output
✗ curl -X POST localhost:8000/login \--header Content-Type: application/json \--data-raw {username:testdriven.io,email:admintestdriven.io,password:testdriven.io}{username:testdriven.io,email:admintestdriven.io}中间件
中间件被用来在每个请求被视图功能处理之前应用逻辑。
Flask
class middleware:def __init__(self, app) - None:self.app appdef __call__(self, environ, start_response):start time.time()response self.app(environ, start_response)end time.time() - startprint(frequest processed in {end} s)return responseapp Flask(__name__)
app.wsgi_app middleware(app.wsgi_app)FastAPI
from fastapi import Requestapp.middleware(http)
async def add_process_time_header(request: Request, call_next):start_time time.time()response await call_next(request)process_time time.time() - start_timeprint(frequest processed in {process_time} s)return responseapp.middleware(http) 装饰器是在 FastAPI 中创建中间件的必备工具。上述中间件计算处理请求所花费的时间。视图函数处理请求后计算总处理时间并将其作为响应头返回。
# flask output(logs)
request processed in 0.0010077953338623047 s
127.0.0.1 - - [22/Sep/2020 18:56:21] GET / HTTP/1.1 200 -# fastapi output(logs)
request processed in 0.0009925365447998047 s
INFO: 127.0.0.1:51123 - GET / HTTP/1.1 200 OK模块化
随着应用程序的发展在某些时候你会想把类似的视图、模板、静态文件和模型组合在一起以帮助把应用程序分解成更小的组件。
Flask
在 Flask 中蓝图被用来实现模块化
# blueprints/product/views.py
from flask import Blueprintproduct Blueprint(product, __name__)product.route(/product1)...# main.pyfrom blueprints.product.views import productapp.register_blueprint(product)FastAPI
同时在 FastAPI 中模块化是通过 APIRouter 实现的
# routers/product/views.py
from fastapi import APIRouterproduct APIRouter()product.get(/product1)...# main.pyfrom routers.product.views import productapp.include_router(product)其他特点 自动文档
Flask
Flask 不会自动创建开箱即用的 API 文档。然而有几个扩展可以处理这个问题比如 flask-swagger 和 Flask RESTX但它们需要额外的设置。
FastAPI
默认情况下FastAPI 支持 OpenAPI 以及 Swagger UI 和 ReDoc。这意味着每个端点都自动从与端点关联的元数据中记录下来。 所有注册的端点都列在这里
此处列出了所有已注册的端点 替代文档 管理应用
Flask
Flask 有一个广泛使用的第三方管理包称为 Flask-Admin用于快速对您的模型执行 CRUD 操作。
FastAPI
截至目前有两个流行的 FastAPI 扩展用于此 FastAPI Admin - 功能性管理面板提供用于对数据执行 CRUD 操作的用户界面。 SQLAlchemy Admin -FastAPI/Starlette 的管理面板可与 SQLAlchemy 模型一起使用。
身份认证
Flask
虽然 Flask 没有原生解决方案但可以使用多个第三方扩展。
FastAPI
FastAPI 通过 fastapi.security 包原生支持许多安全和身份验证工具。通过几行代码您可以将基本的 HTTP 身份验证添加到您的应用程序中
import secretsfrom fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentialsapp FastAPI()security HTTPBasic()def get_current_username(credentials: HTTPBasicCredentials Depends(security)):correct_username secrets.compare_digest(credentials.username, stanleyjobson)correct_password secrets.compare_digest(credentials.password, swordfish)if not (correct_username and correct_password):raise HTTPException(status_codestatus.HTTP_401_UNAUTHORIZED)return credentials.usernameapp.get(/whoami)
def who_ami_i(username: str Depends(get_current_username)):return {username: username}FastAPI 通过 OpenAPI 标准实现 OAuth2 和 OpenID Connect。
查看官方文档中的以下资源以获取更多信息 Security Introhttps://fastapi.tiangolo.com/tutorial/security/ Advanced Security:https://fastapi.tiangolo.com/advanced/security/
其他资源 Web Authentication Methods Comparedhttps://testdriven.io/blog/web-authentication-methods/ Adding Social Authentication to Flask:https://testdriven.io/blog/flask-social-auth/ Session-based Auth with Flask for Single Page Apps:https://testdriven.io/blog/flask-spa-auth/ Securing FastAPI with JWT Token-based Authenticationhttps://testdriven.io/blog/fastapi-jwt-auth/
CORS
CORS跨源资源共享中间件检查请求是否来自允许的来源。如果是则将请求传递给下一个中间件或视图函数。如果不是它会拒绝请求并将错误响应发送回调用者。
Flask Flask 需要一个名为 Flask-CORS 的外部包来支持 CORS
pip install flask-cors基本实现
from flask_cors import CORSapp Flask(__name__)CORS(app)FastAPI
FastAPI 原生支持 CORS
from fastapi.middleware.cors import CORSMiddlewareapp FastAPI()origins [*]app.add_middleware(CORSMiddleware, allow_originsorigins)测试 Flask
import pytest
from flask import Flaskapp Flask(__name__)app.route(/)
def home():return {message: OK}def test_hello():res app.test_client().get(/)assert res.status_code 200assert res.data b{message:OK}\nFastAPI
from fastapi import FastAPI
from fastapi.testclient import TestClientapp FastAPI()app.get(/)
async def home():return {message: OK}client TestClient(app)def test_home():res client.get(/)assert res.status_code 200assert res.json() {message: OK}FastAPI 提供了一个 TestClient。有了它你可以直接用 FastAPI 运行 pytest。有关更多信息请查看官方文档中的测试指南。
部署 生产服务器
Flask
Flask 默认运行开发 WSGIWeb 服务器网关接口应用程序服务器。对于生产环境您需要使用生产级 WSGI 应用服务器例如 Gunicorn、uWSGI 或 mod_wsgi
安装 Gunicorn:
pip install gunicorn启动服务
# main.py
# app Flask(__name__)gunicorn main:appFastAPI
由于 FastAPI 没有开发服务器您将使用 Uvicorn或 Daphne进行开发和生产。
安装 Uvicorn
pip install uvicorn启动服务
python
# main.py
# app FastAPI()uvicorn main:app您可能希望使用 Gunicorn 来管理 Uvicorn以便同时利用并发性通过 Uvicorn和并行性通过 Gunicorn worker
# main.py
# app FastAPI()gunicorn -w 3 -k uvicorn.workers.UvicornWorker main:appDocker
Flask
FROM python3.10-slimWORKDIR /appCOPY requirements.txt .RUN pip install -r requirements.txtCOPY . .EXPOSE 5000CMD [gunicorn, main:app]这是 Flask 最简单的 Dockerfile 之一。要了解如何针对生产对其进行全面配置请查看使用 Postgres、Gunicorn 和 Nginx 教程对 Flask 进行 Docker 化。
FastAPI
sql
FROM python3.10-slimWORKDIR /appCOPY requirements.txt .RUN pip install -r requirements.txtCOPY . .EXPOSE 8000CMD [uvicorn, main:app]同样这是一个非常简单的配置。 FastAPI 作者提供了几个生产就绪的 Dockerfile。有关更多信息请查看官方 FastAPI 文档以及 Dockerizing FastAPI with Postgres、Uvicorn 和 Traefik 教程。
总结 退一步讲Django 和 Flask 是两个最流行的基于 Python 的网络框架FastAPI 是第三大流行框架。不过它们Django 和 Flask的理念非常不同。Flask 比 Django 的优势在于 Flask 是一个微框架。程序结构由程序员自己决定不强制执行。开发者可以在他们认为合适的时候添加第三方扩展来改进他们的代码。也就是说通常情况下随着代码库的增长需要一些几乎所有网络应用都需要的通用功能。这些功能与框架的紧密结合使得终端开发者需要自己创建和维护的代码大大减少。
本文中的代码实例也表达了同样的意思。换句话说FastAPI 包括许多必要的功能。它还遵循严格的标准使你的代码可以生产并更容易维护。FastAPI 的文档也非常完善。
虽然 FastAPI 可能不像 Flask 那样久经考验但越来越多的开发人员正在转向它来提供机器学习模型或开发 RESTful API。切换到 FastAPI 是一个不错的选择。
官方文档 FastAPIhttps://fastapi.tiangolo.com/ Flaskhttps://flask.palletsprojects.com/en/2.0.x/
其他资源 Porting Flask to FastAPI for ML Model Servinghttps://www.pluralsight.com/tech-blog/porting-flask-to-fastapi-for-ml-model-serving/ Why we switched from Flask to FastAPI for production machine learninghttps://towardsdatascience.com/why-we-switched-from-flask-to-fastapi-for-production-machine-learning-765aab9b3679 Awesome Flask:https://github.com/mjhea0/awesome-flask Awesome FastAPI:https://github.com/mjhea0/awesome-fastapi