(Avanzado) Marco web Python FastAPI: un marco API de mayor rendimiento que Flask y Tornada

Prólogo

 

En el artículo anterior, tenía una comprensión preliminar del uso básico de FastAPI, pero si realmente desea implementar FastAPI en el servidor, entonces necesita aprender más y aprender más. Por lo tanto, este artículo se centrará en el entorno de producción de los proyectos FastAPI, como las operaciones específicas de FastAPI en la base de datos, los planos de enrutamiento, la verificación de datos y algunos pozos encontrados por mí mismo, y los compartiré con todos los que están atacando FastAPI.

 

 

Anteproyecto

 

De hecho, FastAPI no tiene una definición de Blueprint. Use el método Include_route para agregar rutas en FastAPI, que también se conoce como Blueprint.

import time
from typing import List
from starlette.templating import Jinja2Templates
from fastapi import Depends, FastAPI, HTTPException
from starlette.staticfiles import StaticFiles
from starlette.templating import Jinja2Templates
from app import models
from app.database.database import SessionLocal, engine
from app.home import user,index


app = FastAPI()

app.mount("/static", StaticFiles(directory="app/static"), name="static") # 挂载静态文件,指定目录
templates = Jinja2Templates(directory="templates") # 模板目录

app.include_router(index.userRouter)
app.include_router(user.userRouter,prefix="/user")

 

Puede ver que los archivos user.py e index.py se introducen en el directorio de inicio. Tenga en cuenta que un objeto de clase APIRouter () debe inicializarse en el archivo (por supuesto, puede elegir heredar si es necesario). El prefijo indica la ruta de la subrutina, más Para el uso de parámetros, consulte la documentación oficial.

# user.pyfrom starlette.templating import Jinja2Templatesfrom app import schemas, models
from app.database.database import get_db
from app.home import crud
from fastapi import Depends, HTTPException, Form
from sqlalchemy.orm import Session
from app.models import User
from sqlalchemy.orm import Session
from fastapi import APIRouter, HTTPException,Request
from fastapi.responses import RedirectResponse

userRouter = APIRouter()
templates = Jinja2Templates(directory="app/templates") # 模板目录

@userRouter.post("/login/", response_model=schemas.UserOut)
async def login(*,request: Request,db: Session = Depends(get_db), username: str = Form(None), password: str = Form(None),):
    if request.method == "POST":
        db_user = db.query(models.User).filter(User.username == username).first()
        if not db_user:
            raise HTTPException(status_code=400, detail="用户不存在")
        print("验证通过 !!!")
        return RedirectResponse('/index')

    return templates.TemplateResponse("user/login.html", {"request": request})

 

Parece mucho más fácil que Flask agregando planos.

 

Admite múltiples métodos de solicitud al mismo tiempo

 

En el ejemplo de inicio de sesión anterior, puedo encontrar que en la solicitud de contexto, realizo el procesamiento lógico de la respuesta juzgando el método de solicitud de ruta, como redirigirlo a la página de inicio de sesión si no es una solicitud de publicación. Entonces debe admitir varios métodos de solicitud al mismo tiempo. Casualmente, no puedo encontrar las instrucciones correspondientes en la documentación de FastAPI. Al principio, estuve confundido por un tiempo. Por lo tanto, solo puede hacer el código fuente.

 

Vaya directamente al archivo donde se encuentra la clase APIRouter y descubra el Nuevo Mundo.

 

 

Hay un método llamado add_api_route en APIRouter, que admite el método http que se pasará como una lista, por lo que se reemplaza por la siguiente escritura:

async def login(*,request: Request,db: Session = Depends(get_db), username: str = Form(None), password: str = Form(None),):
    if request.method == "POST":
        db_user = db.query(models.User).filter(User.username == username).first()
        if not db_user:
            raise HTTPException(status_code=400, detail="用户不存在")
        print("验证通过 !!!")
        return RedirectResponse('/index')

    return templates.TemplateResponse("user/login.html", {"request": request})


async def userList(*,request: Request,db: Session = Depends(get_db)):
    userList = db.query(models.User).all()
    return templates.TemplateResponse("user/user-index.html", {"request": request,'userList':userList})

userRouter.add_api_route(methods=['GET','POST'],path="/login",endpoint=login)
userRouter.add_api_route(methods=['GET','POST'],path="/list",endpoint=userList)

 

Entre ellos, los métodos son palabras muy familiares, escriba el método de solicitud HTTP que desee, la ruta se refiere a la ruta al acceder y el punto final es el método de fondo.

 

Esto resuelve el problema de múltiples métodos de solicitud HTTP al mismo tiempo, y la codificación es más intuitiva y concisa.

 

Base de datos

 

En FastAPI, usamos SQLAlchemy como siempre

 

Inicialice el archivo de base de datos:

from sqlalchemy import create_enginefrom sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# 创建数据库连接URI
SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:[email protected]:3306/blog"

# 初始化
engine = create_engine(
    SQLALCHEMY_DATABASE_URL
)

# 创建DBSession类型
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 创建基类 用于继承  也可以放到初始化文件中
Base = declarative_base()

# 获取数据库会话,用于数据库的各种操作
def get_db():
    db = SessionLocal()

 

Archivos de modelo de base de datos:

from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, DateTime, Text
from sqlalchemy.orm import relationship
from datetime import datetime
from flask_login import  UserMixin
import uuid
from app.database.database import Base


class User(UserMixin,Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    email = Column(String(64),)
    username = Column(String(64), )
    role = Column(String(64), )
    password_hash = Column(String(128))
    head_img = Column(String(128), )
    create_time  = Column(DateTime,default=datetime.now)

    def __repr__(self):
        return '<User %r>' % self.username

# 文章表
class Article(Base):
    __tablename__ = 'article'
    id = Column(Integer, primary_key=True)
    title=Column(String(32))
    author =Column(String(32))
    img_url = Column(Text,nullable=False)
    content=Column(Text,nullable=False)
    tag=Column(String(64),nullable=True)
    uuid = Column(Text,default=uuid.uuid4())
    desc = Column(String(100), nullable=False)
    create_time = Column(DateTime,default=datetime.now)
    articleDetail = relationship('Article_Detail', backref='article')

    def __repr__(self):
        return '<Article %r>' % self.title

 

Aumentar

async def articleDetailAdd(*,request: Request,db: Session = Depends(get_db),d_content:str,uid:int):
    if request.method == "POST":
        addArticleDetail= Article_Detail(d_content=d_content,uid=uid)
        db.add(addArticleDetail)
        db.commit()
        db.refresh(addArticleDetail)
        print("添加成功 !!!")
        return "添加成功"
    return "缺少参数"

 

Eliminar

async def articleDetailDel(*,request: Request,db: Session = Depends(get_db),aid:int):
    if request.method == "POST":
        db.query(Article_Detail).filter(Article_Detail.id == aid).delete()
        db.commit()
        print("删除成功 !!!")
        return "删除成功"
    return "缺少参数"

 

Cambio

async def articleDetailUpdate(*,request: Request,db: Session = Depends(get_db),aid:int,d_content:str):
    if request.method == "POST":
        articleInfo= db.query(Article_Detail).filter(Article_Detail.id == aid).first()
        print(articleInfo)
        if not articleInfo:
            raise HTTPException(status_code=400, detail="no no no !!")

        articleInfo.d_content = d_content
        db.commit()
        print("提交成功 !!!")
        return "更新成功"
    return "缺少参数"

 

Cheque

async def articleDetailIndex(*,request: Request,db: Session = Depends(get_db),):
    articleDetailList = db.query(models.Article_Detail).all()
    return templates.TemplateResponse("articleDetail/articleDetail-index.html", {"request": request,"articleDetailList":articleDetailList})

 

Estos son algunos ejemplos de lo peor: cuando realmente se implementa, no puede ser tan imprudente. Captura incorrecta, reversión de la base de datos y la declaración debe ser rigurosa.

 

Validación de datos

 

En el método de enrutamiento, hay un parámetro llamado response_model, que se usa para limitar el campo de retorno del método de enrutamiento.

 

Ejemplos de documentos oficiales:

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()

class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str = None


@app.post("/user/", response_model=UserOut)
async def create_user(*, user: UserIn):
    return user

 

Esto significa que UserIn se pasa como un parámetro del cuerpo de la solicitud y debe volver al modelo UserOut al regresar.

En el escenario, puede imaginar que el usuario necesita pasar el nombre de usuario y la contraseña al iniciar sesión. Después de que el usuario inicia sesión correctamente, el correo electrónico del nombre de usuario se muestra en la página de inicio y no se muestra la contraseña. Bueno, esto tiene sentido.

 

Por lo tanto, durante las operaciones de la base de datos, puede definir los campos del modelo entrantes y devueltos para limitarlos de manera efectiva. Solo necesita heredar la clase base BaseModel en pydantic, lo que parece tan simple y razonable.

 

Manejo de excepciones

 

Cuando no existen varios recursos http o existen excepciones de acceso, se requieren códigos de estado http y descripciones de excepciones, por ejemplo, error 404 No encontrado, solicitud posterior 422, error del servidor 500, así que cómo generar razonablemente una excepción en el programa, Se vuelve muy importante.

 

Vea cómo usar el manejo de excepciones en FastAPI

from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {"foo": "The Foo Wrestlers"}


@app.get("/items/{item_id}")
async def read_item(item_id: str):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item": items[item_id]}

 

Use HTTPException, pase el código de estado y las instrucciones detalladas, y arroje una excepción cuando ocurra un error lógico.

 

Reescribir HTTPException

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse


class UnicornException(Exception):
    def __init__(self, name: str):
        self.name = name


app = FastAPI()


@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
    return JSONResponse(
        status_code=418,
        content={"message": f"我家热得快炸了..."},
    )


@app.get("/unicorns/{name}")
async def read_unicorn(name: str):
    if name == "yolo":
        raise UnicornException(name=name)
    return {"unicorn_name": name}

 

UnicornException hereda de la clase Exception que viene con Python. Cuando se produce un error del lado del servidor, se genera un error 418 y se adjunta una descripción del error.

 

Personaliza tu propio código de manejo de excepciones

from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException

app = FastAPI()


@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)


@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    return PlainTextResponse(str(exc), status_code=400)


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 3:
        raise HTTPException(status_code=418, detail="开空调啊")
    return {"item_id": item_id}

 

El uso razonable del mecanismo de manejo de excepciones puede hacer que el código del proyecto sea más robusto, el cliente sea más amigable y fácil de mantener.

 

¿Hay algo más?

 

En el vasto documento FastAPI, traté de encontrar algunas funciones fáciles de usar, prácticas y fáciles de usar para compartir con usted, e intenté invertir en el entorno de producción real. En este proceso, aprendí más cosas y experimenté mejor Prestaciones de servicio.

La documentación oficial de FastAPI es muy grande, y hay muchos lugares que no se han popularizado y profundizado, como el cifrado seguro de FastAPI, el uso de middleware, la implementación de aplicaciones, etc. Ja, ven a Japón!

 

Si necesita aprender más sobre FastAPI, puede leer todo para obtener más detalles:

Documento de referencia: https://fastapi.tiangolo.com/tutorial

Supongo que te gusta

Origin www.cnblogs.com/dcpeng/p/12716560.html
Recomendado
Clasificación