一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情。
前言
其实这篇文章是很久之前
写的了,但因为与pity接口自动化平台息息相关,掘金也没有发过此文, 少了这篇文章会显得很突兀。于是我整合了他们,发表出来。
FastApi简介
官网地址: fastapi.tiangolo.com/zh/
FastApi
是最近(具体啥时候开始我也不知道)很火的一个Python web框架
,其实我对他了解也不够多,那咱们来看看他的官方文档吧。
基本上可以瞅到几个关键字,一马当先的就是快。那么她有多快呢,这边写到了Go
,我本身呢是个go语言使用者,身上随身带个if err != nil
,很合逻辑吧!
其他的咱们都可以不用看,那都是虚的,其实我就想知道这玩意有多快
。是不是真的和他标榜的那样,和go肩并肩。
试水
所以我开始了自己的一次尝试,昨天晚上我特意搭建了一个FastApi服务,跑了跑。虽然我本身没用过django,但是大概也知道django的全面,各个组件应有尽有,简直就是精装修,拎包入住即可
。那FastApi呢?曾经有群友形容他是毛坯中的毛坯,意思是啥组件都需要自己写,核心库比不上Flask多,更别说django了,django,yyds!
但是我本身对于新鲜事物还是很好奇的,所以就忍不住体验了一把。如果这是一篇测评文章的话,那我的测评进度可能才到5%,不过就算是这样,我也觉得FastApi应当是一款不错的web框架。
爱之初体验
- 安装fastapi
pip install fastapi
- 安装uvicorn
pip install uvicorn
- 新建一个main.py
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: int
description: Optional[str] = None
price: float
tax: Optional[float] = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
整体风格有点像Flask
,所以上手比较快。这个可能也是我想试试的原因之一。上面的class定义了接受的参数,以往我们用flask接受参数的话一般用request.get_data()或者get_json()
,其实我写惯了go之后还是很不习惯的,因为我还是认为对象
比字典
好使,而且这个item
对象实现了dict()方法,也可以随时转为dict。说句实话,这点确实方便。
- 在main.py同级目录启动服务
uvicorn main:app --reload
--reload
参数指的是热更新部署,意思是可以在代码发生变动的时候自动重启服务,使得代码生效。
方便还是挺方便的。
看看控制台
长的是喜欢的样子!假设我更新下代码:
可以看到服务自动reload了。这点还挺方便的~
计划
计划是把现有的Flask
改为FastApi
,趁着项目还小
,行动起来。有一起学习的小伙伴们,麻烦加我一下!我们一起学!如果不想学的就帮我点个赞吧,希望你不要不识抬举
!(狗头保命)
大概在30篇左右就开始了迁移工作。。。
从Flask到FastApi
我们已经拿到了FastApi体验卡,并且搭建了一个demo服务。说好的要开始学FastApi
,那怎么能从入门到放弃呢?
所以我稍稍看了一下文档,理了一下他里面的门路。所以这篇文章可以算是私货吧,由官方文档加上个人理解组成。我打算先完善比较重要的功能,剩下的到用到的时候再切换
就行了。
为了方便大家能从Flask无缝切换到FastApi
,我也经过一定的实践,结合自己的项目特意编写了这篇文章,可能有些地方没有考虑到,希望大家见谅。文章有点点长,可以不用一口气看完~留着后面啃也可以!
1. 配置项目改造
我们之前会给Flask的app
(pity)初始化一个配置:
其实配置还有
一种用法,就是直接引入Config类,利用Config.字段去获取配置项,所以我们在原项目里面取配置的方法都要修改。
新的方式,我们使用Config.变量
即可。
2. Cors跨域修改
Flask支持跨域
很简单,引入CORS,将app套进去即可。
其实FastApi也不难,其中官网就有对应的例子:
通过引入FastApi自己封装好的CORSMiddleware,即可达到一样的效果。
3. 支持Debug
因为按照我们上一篇的内容,我们通过uvicorn
启动了FastApi服务,但是由于我们是在终端(Terminal)运行的,所以其实打的断点
是无法起作用的,所以我们需要通过运行main.py来达到调试的目的,官网也有类似的教程。
首先导入uvicorn库,然后通过uvicorn.run来运行对应的app
,我经常提到的app,其实是一个FastApi的实例的概念。虽然我给他取名叫pity
,但是我有时候也会叫他app
,希望不要给大家带来困扰。
注意,我这边run方法接受了4个参数,host和port就不多说了,dddd。
reload呢,就是热更新的意思。
至于app='main:pity',main代表的是这个文件的名字: main.py,pity也就是app的名字。main:pity
即代表当前要启动的是main里面的pity。
至于为什么要这么复杂,归根结底还是这个reload
参数,为了能热更新,它需要这些信息,不然会报错:
所以,都是被逼的。
4. Flask-Sqlalchemy变更
其实这个不太属于这块内容,因为有的人甚至没有用到这个模块。
用sqlalchemy的同学可以跳过哦!
其实解决方法呢,就是换成sqlalchemy。所以我们需要按照sqlalchemy的格式去编写ORM。
- 修改models/__init__.py
可以看到我这边读取链接URL,是通过Config来直接获取的。
-
改造models/user.py
随便以user.py为例子:
构造函数可不变,Use类继承的对象就是models/__init__.py里面的Base类,需要注意的是: sqlalchemy需要__tablename__这样一个字段,所以我们需要给它加上,它不会默认生成,不加就报错
。其他地方基本上没有差异。
- 改写增删改查部分
以注册用户
为例,改写方法是去掉以前的User.query.filter_by(),改为session.query(User).filter_by()
,其他的时候差距不大。
注意为什么要用with,因为with执行完毕之后会自动调用__exit__(),也就是会自动关闭session
。
5. 参数校验部分
FastApi呢,和Pydantic进行了强强结合,虽然这一块我还摸得不是很清楚,不过我暂时可以用起来了。
先看下旧版本的,人肉校验器
:
新版本的话,等于说是把参数校验和业务逻辑解耦
了,参数校验放到另外的地方去编写,接口里面只负责处理业务逻辑即可。
新版本接口:
一切的核心都在于这个UserDto
可以看到,我们为UserDto类指定了4个字段,因为都是必填项
,所以未加上默认值,如果我们需要email是非必填
的,则要改成:
class UserDto(BaseModel):
name: str
password: str
username: str
email: str = None
接着就是具体的校验方法了,由于我们的校验规则很简单,所以对所有字段
都是采取的一个方法: field_not_empty
意思是字段不能为空字符串,否则抛出ParamsError,注意这个ParamsError
是我自定义的错误类型,它继承了ValueError。
-
进阶
由于我们的字段校验不通过的返回格式是这样的:
但是这个字段呢,是pydantic帮忙校验好的,所以我们需要添加这么一个方法:
这个方法是针对请求参数校验失败的处理,类似于一个hook,只有请求参数校验失败了,才会走到这个步骤。虽然里面错误信息多,但是我们只取第一条错误信息,不然数据多了展示不方便。
接着我们定义了一个错误字典,目前支持missing
,params
(自己封装的), not_allowed
(参数类型不一致)
看看效果
这样就完成了参数的校验了!
6. 蓝图
在http请求里,接口分类是很关键的事情,所以蓝图这块我们不能跳过,我们粗略讲一下。其实flask里面我们也只是用来给url分组,那我们这里也完成一样的事情就好了。
- 编写接口
APIRouter约等于Blueprint,创建一个APIRouter实例,prefix即url的前缀。
编写接口的时候从@app.route改为@router.post/get即可,变化不大。
-
注册router
router的注册也很简单,和之前蓝图注册类似,通过app.include_router方法即可实现:
由于我这里只改造了user下的router,所以其他的未include进来。
今天的内容就分享到这里吧,没啥好啰嗦的,就给大家拜个早年吧!祝大家新年愉快
。