在前面随笔《基于SqlAlchemy+Pydantic+FastApi的Python开发框架》中介绍了框架总体的内容,其中主要的理念就是通过抽象接口的方式,实现代码的重用,提高开发效率。本篇随笔深入介绍一下FastApi的路由处理部分的内容,通过基类继承的方式,我们可以简化路由器(或者叫Web API 控制器)的基础接口函数的编写,直接重用基类即可。对于子类的一些特殊的重写操作,或者增加自定义的路由接口,也分别介绍如何处理。

1、开发框架的路由处理基类

我在前面介绍了,对于Python中的FastAPI路由对象类,我们也做了抽象的处理,关系如下所示。

绿色部分的BaseController为基类控制器(或基类路由类),黄色部分为我们实际业务的类,也就是子类路由对象。

基类路由类的定义如下所示,通过接受一些泛型参数,实现之类的个性化特性处理。

class BaseController(Generic[ModelType, PrimaryKeyType, PageDtoType, DtoType]):
"""
基类控制器,定义通用的接口和路由
""" def __init__(
self,
crud: BaseCrud[ModelType, PrimaryKeyType, PageDtoType, DtoType],
pagedto_class: Type[PageDtoType],
dto_class: Type[DtoType],
router: APIRouter,
):
self.crud = crud
self.router = router
self.dto_class = dto_class # 用于转换ORM对象为Pydantic对象
self.pagedto_class = pagedto_class # 用于转换请求参数为PageDto对象

由于路由实例也是从外部传入,因此最终我们使用的是一个总的路由实例对象

最终我们在一个总的Api路由类(api.py)中汇总所有的路由信息,如下所示。

api_router = APIRouter()

api_router.include_router(customer.router, prefix="/api/customer", tags=["Customer"])
api_router.include_router(product.router, prefix="/api/product", tags=["Product"]) api_router.include_router(dicttype.router, prefix="/api/dicttype", tags=["DictType"])
api_router.include_router(dictdata.router, prefix="/api/dictdata", tags=["DictData"]) api_router.include_router(user.router, prefix="/api/user", tags=["User"])
api_router.include_router(ou.router, prefix="/api/ou", tags=["OU"])
api_router.include_router(role.router, prefix="/api/role", tags=["Role"]) .....

最后,我们在FastApi入口中注册并接入它们即可

# 添加api总的路由
from api.v1.api import api_router # API
def register_app():
# FastAPI
app = FastAPI(
title=settings.APP_NAME,
version=settings.APP_VERSION,
summary=settings.APP_NAME,
description=settings.DESCRIPTION,
# docs_url=settings.DOCS_URL,
# redoc_url=settings.REDOCS_URL,
# openapi_url=settings.OPENAPI_URL,
# default_response_class=AjaxResponse,
lifespan=register_init,
)
app.include_router(api_router)

这样所有的路由信息全部汇总,就可以出现在fastApi的Swagger文档界面中了。

2、子类路由对基类函数的重写和增加新接口

前面小节介绍了总体路由的接入处理,以及一些默认具有的API接口,但是我们这里还没有介绍它们之间的继承信息。

对于单个业务对象来说,例如对于客户信息的对象,它默认就具有所有的基类API接口。

它们的关系是如何的,如何做到默认继承基类的相关接口的呢?

## app\api\v1\endpoints\customer.py

# 创建路由,用于处理自定义接口
router = APIRouter() # 使用基类控制器,可以继承常规CRUD的接口,并自动生成路由,依赖注入,数据库连接等功能 ——构建方式2
controller = BaseController[Customer, str, CustomerPageDto, CustomerDto](
customer_crud,
pagedto_class=CustomerPageDto,
dto_class=CustomerDto,
router=router,
)
controller.init_router() # 初始化常规CRUD等接口的路由

上面就是对应Customer表的API控制器(路由类)的定义,这个主要就是直接使用基类构造一个对象,并使用该对象的基类函数进行初始化路由地址(默认具有的所有基类API接口)。

如果我们还需要增加一些特殊的API接口,那么我们在router 对象创建后,直接使用它进行增加即可,如下所示

@router.get(
"/by-name",
response_model=AjaxResponse[CustomerDto | None],
summary="根据名称获取记录",
dependencies=[DependsJwtAuth],
)
async def get_by_name(
name: Annotated[str | None, Query()],
request: Request,
db: AsyncSession = Depends(get_db),
):
item = await customer_crud.get_by_name(db, name)
item = CustomerDto.model_validate(item)
return AjaxResponse(item)

这样在运行FastAPI应用后,就可以看到Swagger的文档中增加了对应的接口信息了,如下所示。

如果我们要重写一些控制器基类定义的get的处理方法,如对于用户信息的Get方法,我们除了获得对应的用户信息外,还需要增加一些额外的机构、角色的信息给记录,那么我们可以继承基类并重写Get方法来实现,如下是重写控制器基类的处理代码。

##app\api\v1\endpoints\user.py

# 继承基类,并重写基类某些函数 ——构建方式1
class UserController(BaseController[User, int, UserPageDto, GetCurrentUserInfoDetail]):
def __init__(self):
super().__init__(
user_crud,
pagedto_class=UserPageDto,
dto_class=UserDto,
router=router,
) # 重写基类函数,增加自定义接口处理
async def get(cls, id: int, db: AsyncSession = Depends(get_db)):
item = await user_crud.get(db, id)
if not item:
raise ItemNotFoundException() dto = GetCurrentUserInfoDetail.model_validate(item) # 增加角色名称列表
roles = await role_crud.get_roles_by_user(db, id)
dto.rolenames = [role.name for role in roles] # 增加角色名称列表 # 增加机构名称列表
ous = await ou_crud.get_ous_by_user(db, id)
dto.ounames = [ou.name for ou in ous] # 增加机构名称列表 dto.issuperadmin = (
dto.rolenames.count("超级管理员") > 0
) # 增加是否超级管理员字段
dto.isadmin = (
dto.issuperadmin or dto.rolenames.count("管理员") > 0
) # 增加是否管理员字段
return AjaxResponse(dto) controller = UserController() controller.init_router() # 初始化常规CRUD等接口的路由

所以,综上的处理方式,我们看到,如果是增加一些接口,我们可以直接用基类控制器的实例对象来处理即可(简单),如果需要重写某些基类的接口处理函数,那么我们继承基类构建之类,并提供重写函数,然后实例化子类对象,初始化路由处理即可。

然后通过在总的路由处理Python类中统一引入即可。

##app\api\v1\api.py
from fastapi import APIRouter
from api.v1.endpoints import (customer, product,dicttype, dictdata, tablenumber, systemparams, systemparamsdir,)
from api.v1.endpoints import ( login,user,ou,role, loginlog, operationlog, systemtype, blackip, function, menu, roledata, fieldpermit, fielddomain)
************** api_router = APIRouter() api_router.include_router(customer.router, prefix="/api/customer", tags=["Customer"])
api_router.include_router(product.router, prefix="/api/product", tags=["Product"])
api_router.include_router(dicttype.router, prefix="/api/dicttype", tags=["DictType"])
api_router.include_router(dictdata.router, prefix="/api/dictdata", tags=["DictData"])
api_router.include_router(user.router, prefix="/api/user", tags=["User"])
api_router.include_router(ou.router, prefix="/api/ou", tags=["OU"])
api_router.include_router(role.router, prefix="/api/role", tags=["Role"]) ..............

然后我们在Main函数中抽离相关的处理路逻辑。

import uvicorn
from pathlib import Pathfrom core.config import settings
from core.register_app import register_app app = register_app()if __name__ == "__main__":
try:
config = uvicorn.Config(
app=f"{Path(__file__).stem}:app",
reload=True,
host=settings.SERVER_IP,
port=settings.SERVER_PORT,
log_config="app/uvicorn_config.json", # 日志配置
)
server = uvicorn.Server(config)
server.run()
except Exception as e:
raise e

在 register_app 函数中统一处理所有相关的逻辑即可,这样可以简化入口的处理复杂度。

##app\core\register_app.py 
def register_app():
# FastAPI
app = FastAPI(
title=settings.APP_NAME,
version=settings.APP_VERSION,
summary=settings.APP_NAME,
description=settings.DESCRIPTION,
lifespan=register_init,
)
# 日志
register_logger()
# 静态文件
register_static_file(app)
# 中间件
register_middleware(app)
# 路由
register_router(app)
# 全局异常处理
register_exception(app) return app

基于SqlAlchemy+Pydantic+FastApi的Python开发框架的路由处理的更多相关文章

  1. flask - fastapi (python 异步API 框架 可以自动生成swagger 文档) 常用示例 以及整合euraka nacos

    flask - fastapi    (python 异步API 框架  可以自动生成swagger 文档)  常用示例: 之前使用 flask 需要手动写文档, 这个可以自动生成, fastapi ...

  2. RDIFramework.NET — 基于.NET的快速信息化系统开发框架 — 系列目录

    RDIFramework.NET — 基于.NET的快速信息化系统开发框架 — 系列目录 RDIFramework.NET,基于.NET的快速信息化系统开发.整合框架,给用户和开发者最佳的.Net框架 ...

  3. RDIFramework.NET — 基于.NET的快速信息化系统开发框架 - 5.3 数据库连接管理模块

    RDIFramework.NET — 基于.NET的快速信息化系统开发框架 5.3 数据库连接管理模块 5.3 数据库连接管理模块 我们经常可以看到很多软件直接把数据库连接字符串放在软件执行目录下的配 ...

  4. 基于DDD的现代ASP.NET开发框架--ABP系列之3、ABP分层架构

    基于DDD的现代ASP.NET开发框架--ABP系列之3.ABP分层架构 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:ht ...

  5. 基于DDD的现代ASP.NET开发框架--ABP系列之2、ABP入门教程

    基于DDD的现代ASP.NET开发框架--ABP系列之2.ABP入门教程 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boi ...

  6. 基于DDD的现代ASP.NET开发框架--ABP系列之1、ABP总体介绍

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之1.ABP总体介绍 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)” ...

  7. 基于webpack实现多html页面开发框架一 准备工作

    本系列主要介绍如何基于webpack实现多html页面开发框架,这里不讲webpack的基本概念,废话不多说,直奔主题! 前置条件: 1.安装node环境,自己去官网下载安装 2.新建文件夹webpa ...

  8. 《精通并发与Netty》学习笔记(07 - 基于Thrift实现Java与Python的RPC调用)

    上节我们介绍了基于Thrift实现java与java的RPC调用,本节我们基于Thrift实现Java与Python的RPC调用 首先,修改data.thirft文件,将命名空间由java改为py n ...

  9. 向大家介绍我的新书:《基于股票大数据分析的Python入门实战》

    我在公司里做了一段时间Python数据分析和机器学习的工作后,就尝试着写一本Python数据分析方面的书.正好去年有段时间股票题材比较火,就在清华出版社夏老师指导下构思了这本书.在这段特殊时期内,夏老 ...

  10. 基于股票大数据分析的Python入门实战(视频教学版)的精彩插图汇总

    在我写的这本书,<基于股票大数据分析的Python入门实战(视频教学版)>里,用能吸引人的股票案例,带领大家入门Python的语法,数据分析和机器学习. 京东链接是这个:https://i ...

随机推荐

  1. lvs的nat和dr模式混合用

    机器部署信息 lvs : 10.0.0.200  vip 10.0.0.19 外网IP , 172.168.1.19 内网IP dr rs: 10.0.0.200 vip 10.0.0.18 rip ...

  2. Vue 在父(子)组件引用其子(父)组件方法和属性

    Vue 在父(子)组件引用其子(父)组件方法和属性   by:授客 QQ:1033553122   开发环境   Win 10 element-ui  "2.8.2" Vue 2. ...

  3. Git 克隆仓库报unable to get local issuer certificate错误解决方法

    Git 克隆仓库报unable to get local issuer certificate错误解决方法 By:授客 QQ:1033553122 问题描述 克隆gitlab上的仓库,报错,如下 $ ...

  4. Fiddler篡改请求和响应数据

    Fiddler标记断点后,我们可以通过篡改请求或响应数据,来模拟客户端请求和服务器响应. 一.打断点的方式 1.1 工具栏设置断点 工具栏勾选断点类型进行断点,路径:Rules->Automat ...

  5. cpu亲和性相关函数和宏 基础讲解[cpu_set_t]

    cpu亲和性相关函数和宏讲解: 写在前面: 我在查找关于linux cpu宏函数没看到有对宏函数基础的.详细的讲解,笔者便通过官方文档入手,对次进行的翻译和理解希望能帮到对这方面宏有疑惑的读者 exp ...

  6. B站上教虚幻引擎做游戏的博主 —— 谌嘉诚

    个人主页地址: https://space.bilibili.com/31898841/ 课程地址: https://www.bilibili.com/video/BV164411Y732/

  7. 在docker容器中创建用户组和用户,并且多用户共用一个anaconda环境

    背景: 实验室可以使用一个浪潮的AI计算平台,该平台运行的都是docker容器,并且不能联网,因此谁要是想要安装什么软件的话就需要自己单独打包镜像到平台上,大致步骤为: 1.   在平台的镜像管理中找 ...

  8. Ubuntu18.04server 双网卡,开机自动设置路由并启动校园网网络认证程序(Ubuntu开机自动设置路由,开机自启动应用程序)

    本博主为高龄在校生,实验室服务器需要假期时候无人守候也能实现自动登录校园网从而实现网络连接,以使实验室同学在家也可以使用校园vpn连接服务器. 由于假期时候实验室没有人,而假期实验室可能会出现断电断网 ...

  9. UE Websocket 通信

    项目中遇到UE需要对接Websocket协议接收实时数据. 所以需要实现一个Websocket Client的功能. 由于UE引擎已经集成了Websocket库(基于libwebsocket),可以通 ...

  10. canvas实现手动绘制矩形

    开场白 虽然在实际的开发中我们很少去绘制流程图 就算需要,我们也会通过第3方插件去实现 下面我们来简单实现流程图中很小的一部分 手动绘制矩形 绘制一个矩形的思路 我们这里绘制矩形 会使用到canvas ...