fastapi之根据model生成schema和router
概述
fastapi没有对应的admin,所以在需要配置后端的时候,会比较麻烦,每个接口都需要自己手动写。
但是很多时候我们可能需要一个比较标准的东西,比如…一个装饰器
通过装饰器装饰model就可以自动注册路由,自动生成对应的标准方法,再根据更多的一些自定义配置,甚至不需要自己手动写schema,然后不需要自己单独写路由相关的东西。(相当于给sqlalchemy的model增加django的model的部分功能)
原理
通过type动态生成对应的model。再自动注册到服务器
使用说明
使用方法如下:
#创建model的时候,get_basemodel装饰系统
@get_basemodel
class User(Base):
__tablename__='users'
id = Column(Integer, primary_key=True, index=True)
email = Column(String(64), unique=True, index=True,default="chise123@live.com")
hashed_password = Column(String(64))
is_active = Column(Boolean, default=True)
items = relationship("Item", back_populates="owner")
在main里面的router注册:
# user是model,app是写入系统,
User.__model__.write2route('/user',app,User,get_db = SessionLocal())
这是一个demo,做技术验证用,之后会逐步完善该功能,
装饰器代码
这里只是有一个list的方法(对应methods的get)
# -*- encoding: utf-8 -*-
"""
@File : test_selializers.py
@Time : 2020/4/1 1:03
@Author : chise
@Email : chise123@live.com
@Software: PyCharm
@info :尝试将model转为basemodel的类,实现操作
"""
from pydantic import BaseModel, Field
from typing import NewType
from sqlalchemy import Integer, Table
UserId = NewType('UserId', int)
# admin_basemodel = []
from fastapi import APIRouter
class RouterBaseModel(BaseModel):
"""这个类主要是给生成的schema增加操作"""
@staticmethod
def list(model, db): # 对应get方法
"""methods=get,读取列表"""
def res():
return db.query(model).all()
# print(model.__table__.select())
return res
def write2route(self, ul, route: APIRouter, model, get_db):
"""注册到路由"""
route.get(ul)(self.list(model, get_db))
class Config:
orm_mode = True
def get_basemodel(cls):
"""通过读取model的信息,创建schema"""
model_name = cls.__name__
# mappings为从model获取的相关配置
__mappings__ = {} # {'name':{'field':Field,'type':type,}}
for filed in cls.__table__.c:
filed_name = str(filed).split('.')[-1]
if filed.default:
default_value = filed.default
elif filed.nullable:
default_value = ...
else:
default_value = None
# 生成的结构: id:int=Field(...,)大概这样的结构
res_field = Field(default_value, description=filed.description) # Field参数
if isinstance(filed.type, Integer):
tp = NewType(filed_name, int)
else:
tp = NewType(filed_name, str)
__mappings__[filed_name] = {'tp': tp, 'Field': res_field}
res = type(model_name, (RouterBaseModel,), __mappings__)
# 将schema绑定到model
cls.__model__ = res()
return cls
实现效果