FastAPI

2,915 阅读2分钟

介绍

FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用基于类型提示的 Python 3.6 及更高版本。

官网介绍

依赖库的安装

pip install fastapi

pip install uvicorn

第一个程序

源码

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def read_root():
    return {"Hello": "World"}

运行服务:

uvicorn main:app --reload

然后浏览器地扯栏输入: http://127.0.0.1:8000 即可看到效果。

扩展功能

表单数据交互

注意: 如果要使用request.form()支持表单“解析”,则为必需 python-multipart 。

pip install python-multipart

如果python-multipart 库没有安装的话,可能会提示:{"detail":"There was an error parsing the body"} 这种错误。

目录结构如下

project
    templates
        form.html # 表单模板文件
        show.html # 显示表单提交过来的数据
    main.py

main.py

from fastapi import FastAPI, Form
from starlette.templating import Jinja2Templates
from starlette.requests import Request

app = FastAPI()

# 设置模板存放路径
template = Jinja2Templates(directory='templates')

@app.get('/form')  # 接受get请求
async def get_user(request: Request):
    return template.TemplateResponse('form.html', {'request': request})


@app.post('/user/')  # 接受post请求
async def get_user(request: Request,
                   username: str = Form('username'),  # 直接去请求体里面获取username键对应的值并自动转化成字符串类型
                   password: str = Form('password')
                   ):
    print(username, type(username))
    print(password, type(password))
    return template.TemplateResponse('show.html', {
        'request': request,
        'username': username, # 传参给模板
        'pwd': password # 传参给模板
    })


if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app=app, host='127.0.0.1', port=8000)

form.html

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link rel="stylesheet" type="text/css" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>

<div class="container">
    <div class="row">
        <form action="/user/" method="post">
            <div class="form-group">
                <label for="exampleInputEmail1">账号</label>
                <input type="text" name="username" class="form-control" id="exampleInputEmail1" placeholder="账号">
            </div>
            <div class="form-group">
                <label for="exampleInputPassword1">密码</label>
                <input type="password" name="password" class="form-control" id="exampleInputPassword1" placeholder="密码">
            </div>
            <button type="submit" class="btn btn-success">提交</button>
        </form>
    </div>
</div>

</body>
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</html>

show.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>显示出表单提交过来的数据</title>
</head>
<body>

<p>账号是:{{ username }}</p>
<p>密码是:{{ pwd }}</p>
</body>
</html>

浏览器访问 http://127.0.0.1:8000/form

文件上传

单文件上传

目录结构如下:

project
    static
    templates
        file_upload.html 
        file.html
    main.py

main.py

from fastapi import FastAPI, Form, File, UploadFile
from starlette.templating import Jinja2Templates
from starlette.requests import Request
import uuid

app = FastAPI()

# 设置模板存放路径
template = Jinja2Templates(directory='templates')

@app.get('/file_upload')
async def index(request: Request):  # async加了就支持异步  把Request赋值给request
    return template.TemplateResponse('file_upload.html', {'request': request})


@app.post('/file/')  # 接受post请求
async def get_user(request: Request,
                   file: bytes = File('file'),  # # 把文件对象转为bytes类型
                   file_obj: UploadFile = File('file_obj'),  # UploadFile转为文件对象
                   info: str = Form('info')  # 获取普通键值对
                   ):
    # 保存上传的文件到static中
    path = 'static/' + str(uuid.uuid4()) + '.jpg' 
    contents = await file_obj.read()
    with open(path, "wb") as f:
        f.write(contents)

    return template.TemplateResponse('file.html', {
        'request': request,
        'file_size': len(file),
        'file_name': file_obj.filename,
        'info': info,
        'file_content_type': file_obj.content_type
    })


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app=app, host='127.0.0.1', port=8000)

file_upload.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>单文件上传</title>
</head>
<body>

<form action="/file/" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="file" name="file_obj">
    <input type="text" name="info">
    <input type="submit" value="上传">
</form>

</body>
</html>

file.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h2>单个文件</h2>
<h1>{{ file_size }}</h1>
<h1>{{ file_name }}</h1>
<h1>{{ info }}</h1>
<h1>{{ file_content_type }}</h1>

</body>
</html>

运行服务后浏览器访问:http://127.0.0.1:8000/file_upload

多文件上传

目录结构如下:

project
    static
    templates
        file_upload.html 
        file.html
    main.py

main.py

from fastapi import FastAPI, Form, File, UploadFile
from starlette.templating import Jinja2Templates
from starlette.requests import Request
from typing import List

app = FastAPI()

# 设置模板存放路径
template = Jinja2Templates(directory='templates')

@app.get('/file_upload')
async def index(request: Request):  # async加了就支持异步  把Request赋值给request
    return template.TemplateResponse('file_upload.html', {'request': request})


@app.post('/file/')  # 接受post请求
async def get_user(request: Request,
                   file_list: List[UploadFile]=File('file_list'),  # UploadFile转为文件对象
                   ):
    # 保存上传的多个文件
    for file in file_list:
        contents = await file.read()
        filename = file.filename # 这里使用的是保存原文件名,如果需要随机文件名的话,请自定义
        with open("static/" + filename, "wb") as f:
            f.write(contents)

    return template.TemplateResponse('file.html', {
        'request': request,
        'file_names': [file_obj.filename for file_obj in file_list],
    })


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app=app, host='127.0.0.1', port=8000)

file_upload.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>多文件上传</title>
</head>
<body>

<form action="/file/" method="post" enctype="multipart/form-data">
    <input type="file" name="file_list" multiple>
    <input type="submit" value="上传">
</form>

</body>
</html>

file.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h2>多个文件名</h2>
{% for i in file_names %}
<h2>{{ i }}</h2>
{% endfor %}

</body>
</html>