fastapi 大型应用_FastAPI使用小结

以一个实际构建API的例子介绍FastAPI在已有数据情况下的简单应用

简介

FastAPI是一个现代、快速(高性能)的 Web 框架,基于标准 Python 类型提示,使用 Python 3.6+ 构建 API。

主要特征是:

高速:与NodeJS和Go相当,拥有高性能。 现有最快的Python框架之一。

快速编码:将功能开发速度提高约200%至300%。

更少的Bug:减少约40%的人为(开发人员)导致的错误。

直观:更好的编辑支持。补全任何地方。更少的调试时间。

简单:方便使用和学习。减少阅读文档的时间。

简介:最小化代码重复。每个参数声明的多个要素。更少的错误。

健壮:获取便于生产的代码。带自动交互式文档。

基于标准:基于(并完全兼容)API 的开放标准:OpenAPI(以前称为Swagger)和 JSON Schema。

需求及依赖

在Mysql中数据库中有一个Gene表,开发接口实现对这个表的数据的增删改查。

Python版本需要3.7+,依赖包如下:

certifi == 2020.4.5.1

click == 7.1.1

fastapi == 0.54.1

h11 == 0.9.0

importlib-metadata == 1.6.0

inflect == 4.1.0

pydantic == 1.4

PyMySQL == 0.9.3

sqlacodegen == 2.1.0

SQLAlchemy == 1.3.16

starlette == 0.13.2

uvicorn == 0.11.3

websockets == 8.1

wincertstore == 0.2

zipp == 3.1.0

FastAPI是一个轻量级的框架,与数据库的通信是通过SQLAlchemy包来实现的。

文件结构

以sql_app为项目名,简单的文件结构如下:

.

└── sql_app

├── __init__.py

├── crud.py

├── database.py

├── main.py

├── models.py

└── schemas.py

__init__.py文件只是一个空文件,但它告诉Python把sql_app作为一个模块来使用。下面对每个文件进行说明。

数据库连接

在sql_app/database.py文件中,创建与数据库的连接,整体代码如下:

from sqlalchemy import create_engine

from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "mysql+pymysql://user:[email protected]:3306/cloud" #使用pymysql作为驱动,cloud是数据库名称

engine = create_engine(

SQLALCHEMY_DATABASE_URL

)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base() #返回一个类,后续作为数据库模型的基类(ORM模型)

创建模型

sql_app/models.py文件中是数据库的对应SQLAlchemy模型,如果数据库已经数据存在。可以使用sqlacodegen直接生成每个表的model:

sqlacodegen --outfile=models.py mysql://user:[email protected]:3306/cloud

如果不指定outfile,则会直接在屏幕上输出。

from sqlalchemy import CHAR, Column, DateTime, ForeignKey, Index, String

from sqlalchemy.dialects.mysql import INTEGER, LONGTEXT, SMALLINT, TINYINT

from sqlalchemy.orm import relationship

from .database import Base

class Gene(Base):

__tablename__ = 'Gene'

id = Column(INTEGER(11), primary_key=True)

gene = Column(String(50, 'utf8mb4_unicode_ci'), nullable=False)

summary = Column(LONGTEXT)

publish_time = Column(DateTime, nullable=False)

edit_time = Column(DateTime, nullable=False)

content = Column(LONGTEXT)

status = Column(SMALLINT(6), nullable=False)

如果有外键依赖,sqlacodegen也可以完美的生成,无需手动。对于那些字段多的表,而且还有N个需要弄的表,sqlacodegen可以极大的提升效率。

创建Pydantic模型

Pydantic可以基于Python的类型提示来进行数据验证。我们使用schmas.py来保存Pydantic模型,以便和保存SQLAlchemy模型的models.py文件进行区分。

from datetime import datetime

from pydantic import BaseModel

class GeneBase(BaseModel):

gene: str

class GeneCreate(GeneBase):

summary: str

publish_time: datetime

edit_time: datetime

content: str

status: int

class Gene(GeneBase):

id: int

summary: str

publish_time: datetime

edit_time: datetime

status: int

class Config:

orm_mode = True # 为Pydantic开启验证

Pydantic的orm_model将告诉Pydantic模型读取数据,它不仅字典,还是ORM模型(或具有属性的任何其他任意对象)。因此,Pydantic模型与ORM兼容,我们可以在接口路径操作中的response_model参数中声明它。

CRUD

接着就是数据库的增删改查操作

from sqlalchemy.orm import Session

from . import models, schemas

def get_gene(db: Session, gene_id: int):

return db.query(models.Gene).filter(models.Gene.id == gene_id).first()

def get_gene_by_name(db: Session, gene_name: str):

return db.query(models.Gene).filter(models.Gene.gene == gene_name).first()

def get_genes(db: Session, skip: int = 0, limit: int = 100):

return db.query(models.Gene).offset(skip).limit(limit).all()

def create_gene(db: Session, gene: schemas.GeneCreate):

db_gene = models.Gene(gene=gene.gene, summary=gene.summary,publish_time=gene.publish_time,edit_time=gene.edit_time, content=gene.content,auditor_id=gene.auditor_id,author_id=gene.author_id, status=gene.status)

db.add(db_gene)

db.commit()

db.refresh(db_gene)

return db_gene

def update_gene(db: Session, gene: schemas.GeneCreate):

db.query(models.Gene).filter(models.Gene.gene == gene.gene).update(gene)

db.commit()

return db.query(models.Gene).filter(models.Gene.gene == gene.gene).first()

def delete_gene(db: Session, gene_id: int):

db.query(models.Gene).filter(models.Gene.id == gene_id).delete()

db.commit()

return {'Result': '删除成功'}

API

最后就是需要实现的API接口了,放在main.py里面。

from typing import List

from fastapi import Depends, FastAPI, HTTPException

from sqlalchemy.orm import Session

from . import crud, schemas

from .database import SessionLocal

app = FastAPI(

title="Gene接口项目",

description="通过接口实现Gene表的增删改查",

version="0.1.0",

openapi_url="/api/v1/api.json",

)

def get_db():

db = ''

try:

db = SessionLocal()

yield db

finally:

db.close()

@app.post("/genes/", response_model=schemas.Gene, summary='新增基因表', description='json格式以post方式提交')

def create_gene(gene: schemas.GeneCreate, db: Session = Depends(get_db)):

db_gene = crud.get_gene_by_name(db, gene_name=gene.gene)

if db_gene:

raise HTTPException(status_code=400, detail=f"{gene.gene}基因已存在")

return crud.create_gene(db=db, gene=gene)

@app.post('/genes/delete/{gene_id}', summary='删除基因信息', description='根据基因ID删除基因信息')

def del_gene(gene_id: int, db: Session = Depends(get_db)):

db_user = crud.get_gene(db, gene_id)

if db_user is None:

raise HTTPException(status_code=404, detail="基因id错误或id不存在")

return crud.delete_gene(db, gene_id)

@app.post("/genes/update", response_model=schemas.Gene, summary='更新已有基因表', description='json格式以post方式提交')

def update_gene(gene: schemas.GeneCreate, db: Session = Depends(get_db)):

db_gene = crud.get_gene_by_name(db, gene_name=gene.gene)

if db_gene is None:

raise HTTPException(status_code=400, detail=f"{gene.gene}基因不存在")

return crud.update_gene(db=db, gene=gene)

@app.get("/genes/", response_model=List[schemas.Gene], summary='获取基因列表', description='/genes/?skip=0&limit=5, 无参数返回所有结果')

def read_users(skip: int = 0, limit: int = 5, db: Session = Depends(get_db)):

users = crud.get_genes(db, skip=skip, limit=limit)

return users

@app.get("/genes/{gene_id}", response_model=schemas.Gene, summary='根据基因id获取基因信息', description='如/genes/1')

def read_user(gene_id: int, db: Session = Depends(get_db)):

db_gene = crud.get_gene(db, gene_id=gene_id)

if db_gene is None:

raise HTTPException(status_code=404, detail="基因id错误或id不存在")

return db_gene

@app.get("/genes/{gene}", response_model=schemas.Gene, summary='根据基因名称获取基因信息', description='如/genes/EGFR')

def read_user(gene: str, db: Session = Depends(get_db)):

db_user = crud.get_gene_by_name(db, gene_name=gene)

if db_user is None:

raise HTTPException(status_code=404, detail="基因名称错误或基因不存在")

return db_user

通过装饰器实现路由和参数传递方法

启动

使用uvicorn启动

uvicorn sql_app.main:app --reload

本文首发于公众号:柠檬培养师(ID: yantinger90),欢迎关注!

你可能感兴趣的:(fastapi,大型应用)