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

  实现效果

posted @ 2020-04-02 15:43  tiana_Z  阅读(1817)  评论(0编辑  收藏  举报