如何快速上手FastAPI(下篇)

前言

在上一篇文章中,我们使用FastAPI编写了一个Flask风格的demo。在这篇文章里我们继续接着上篇的内容对FastAPI进行探究,这里面就包括了请求参数的处理,数据库的连接等。好了闲话少说,现在就开始这篇的内容。

获取路径参数

  1. 跟flask框架一样,fastapi也提供从url中获取参数的能力,具体怎么获取的我们用例子说明一些,代码如下所示:
├── app
│   ├── api
│   │   ├── __init__.py
│   │   └── users.py
│   ├── __init__.py
├── manage.py

2. 打开app/api/users.py文件,键入如下代码:

# app/api/users.py
@users.get("/get_user/{id}")
async def get_user_by_id(id: int):
    if id > 0:
        return {"username": "admin", "msg": "success", "code": 200}
    return {"msg": "failed", "code": 401}

3. 启动服务,并测试

分别打开两个bash,输入以下命令

curl -X GET "http://192.168.2.124:9000/api/get_user/0"
{"msg":"failed","code":401}% 

curl -X GET "http://192.168.2.124:9000/api/get_user/10"
{"username":"admin","msg":"success","code":200}% 

服务日志信息如下

python manage.py 
INFO:     Started server process [65515]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
INFO:     192.168.2.207:54530 - "GET /api/get_user/0 HTTP/1.1" 200 OK
INFO:     192.168.2.207:54532 - "GET /api/get_user/10 HTTP/1.1" 200 OK

获取表单数据

当我们需要从表单中获取用户输入的数据使这个使用就需要使用到Form了

  1. 想要使用Form就需要提前安装python-multipart这个库
pip install python-multipart -i https://pypi.tuna.tsinghua.edu.cn/simple

2. 在视图函数中使用Form对象,具体代码如下所示:

# app/api/users.py
from fastapi import APIRouter, Form

users = APIRouter()


@users.post("/login")
async def login(username: str = Form(), password: str = Form()):
    if username and password:
        return {"msg": "success", "code": 200}

    return {"msg": "failed", "code": 401}

运行测试结果如下所示

curl -X POST -F "username=admin" -F "password=admin" "http://192.168.2.124:9000/api/login"
{"msg":"success","code":200}% 

# 服务器运行日志输出如下
python manage.py 
INFO:     Started server process [65590]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
INFO:     192.168.2.207:54534 - "POST /api/login HTTP/1.1" 200 OK

配置数据库和创建数据模型

很多web大都会提供一些orm的插件或者功能,例如Django就内置了orm,但是与之不一样的地方是像flask和fastapi这些小型框架却没有内置相对应的orm框架,而另辟蹊径采用插件集成的方式来支持数据的操作,这样做的好处是灵活,选择多。

  1. 安装tortoise-orm和aiomysql驱动

我们选择tortoise-orm这个第三方的orm框架,这个框架是参考django内置orm开发的

pip install tortoise-orm -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install aiomysql -i https://pypi.tuna.tsinghua.edu.cn/simple

2. 定义数据模型

# touch  app/models/models.py创建模型文件

from tortoise import fields
from tortoise.models import Model


class User(Model):
    id = fields.IntField(pk=True)
    username = fields.CharField(max_length=30, unique=True, description="用户名")
    password = fields.CharField(max_length=128, description="密码")

3. 配置数据连接信息和初始化数据库

from fastapi import FastAPI

from tortoise.contrib.fastapi import register_tortoise


def create_app() -> FastAPI:
    app = FastAPI()

    register_rotuer(app)
    register_db(app)

    return app


def register_rotuer(app: FastAPI) -> None:
    """注册路由"""
    from app.api import routers
    app.include_router(routers)


def register_db(app: FastAPI) -> None:
    """"初始化数据库并根据数据模型生成对应的表"""
    register_tortoise(
            app, 
            db_url="mysql://root:root12345678@192.168.2.124:3306/item_name",
            modules={"models": ["app.models.models"]},# 这是一个列表用来指明我们的模型文件的路径
            generate_schemas=True,
            add_exception_handlers=True)

测试运行,登录mysql查看是否生成了数据表

python manage.py 
INFO:     Started server process [66742]
INFO:     Waiting for application startup.
/home/test/env/lib/python3.10/site-packages/aiomysql/cursors.py:239: Warning: Table 'user' already exists
  await self._query(query)
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)

查看是否创建了数据表

mysql> desc user;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int          | NO   | PRI | NULL    | auto_increment |
| username | varchar(30)  | NO   | UNI | NULL    |                |
| password | varchar(128) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

在视图函数中操作模型数据

fastapi在视图函数中操作模型数据跟在flask中操作是类似的,具体如下所示

# app/api/users.py

from fastapi import APIRouter, Form

from app.models.models import User

users = APIRouter()


@users.post("/login")
async def login(username: str = Form(), password: str = Form()):
    if username and password:
        return {"msg": "success", "code": 200}

    return {"msg": "failed", "code": 401}


@users.get("/get_users")
async def get_users():
    return {"msg": "success", "code": 200}


@users.get("/get_user/{id}")
async def get_user_by_id(id: int):
    if id > 0:
        return {"username": "admin", "msg": "success", "code": 200}
    return {"msg": "failed", "code": 401}


@users.post("/add")
async def add(username: str = Form(), password: str = Form()):
    if username and password:
        u = await User.create(username=username, password=password)
        if u:
            return {"msg": "create user success", "code": 200}

    return {"msg": "create user failed", "code": 403}


@users.get("/get_user/{id}")
async def get_user(id: int):
    if id:
        data = await User.filter(id=id).first()
        return {"data": data, "msg": "success", "code": 200}
    return {"data": "", "msg": "success", "code": 200}


@users.post("/update_user")
async def update_user(id: str = Form(), name: str = Form()):
    if name and id:
        id = int(id)
        await User.filter(id=id).update(username=name)
        return {"msg": "success", "code": 200}
    
    return {"msg": "failed", "code": 400}


@users.get("/delete_user/{id}")
async def delete(id: int):
    if id:
        await User.filter(id=id).delete()
        return {"msg": "success", "code": 200}

    return {"msg": "failed", "code": 400}

运行测试结果如下所示:

curl -X POST -F "username=admin3" -F "password=admin3" "http://192.168.2.124:9000/api/add"
{"msg":"create user success","code":200}% 

curl -X GET "http://192.168.2.124:9000/api/get_user/1"                                    
{"username":"admin","msg":"success","code":200}%  

curl -X POST -F "id=2" -F "name=admin2" "http://192.168.2.124:9000/api/update_user"
{"msg":"success","code":200}% 

curl -X GET "http://192.168.2.124:9000/api/delete_user/2"
{"msg":"success","code":200}% 

# 服务器运行输出日志如下
python manage.py 
INFO:     Started server process [67038]
INFO:     Waiting for application startup.
/home/test/env/lib/python3.10/site-packages/aiomysql/cursors.py:239: Warning: Table 'user' already exists
  await self._query(query)
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
INFO:     192.168.2.207:54572 - "POST /api/add HTTP/1.1" 200 OK
INFO:     192.168.2.207:54574 - "GET /api/get_user/1 HTTP/1.1" 200 OK
INFO:     192.168.2.207:54576 - "POST /api/update_user HTTP/1.1" 200 OK
INFO:     192.168.2.207:54578 - "GET /api/delete_user/2 HTTP/1.1" 200 OK

demo程序最终目录结构如下所示:

.
├── app
│   ├── api
│   │   ├── __init__.py
│   │   └── users.py
│   ├── __init__.py
│   ├── models
│   │   ├── __init__.py
│   │   ├── models.py
├── manage.py

小结

通过前后两篇文章我们大概知道了怎么去使用fastapi和其他插件来组织和编写web应用服务,虽然这其中的细节没有我没有细说,但是我觉得目前懂得怎么用就行了,细节方面我们在慢慢的进行补充就行了,fastapi的官方文档还是比较清晰易懂的(总之一句话有手就行,哈哈哈)。谢谢你能看到结尾,希望能帮到正在学习fastapi这个框架的你吧。