A package to generate a CRUD routers and endpoints in a very simple way. Based on SQLAlchemy asynchronous operation and schema.
MIT License
pip install fastapi-simple-crud
A package to generate CRUD routers and API in a very simple way. Based on SQLAlchemy asynchronous operation and schema.
ExtendedRouter
disable_crud
for both SimpleRouter()
and ExtendedRouter()
(previously disable_simple_crud
and disable_extended_crud
arguments)SimpleRouter()
and ExtendedRouter()
be accessed from their objectRouterMap.update_map()
can be used to update ExtendedRouter()
from fastapi import FastAPI
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from fastapi_simple_crud import RouterMap
engine = create_async_engine("sqlite+aiosqlite:///./test.db", echo=True, future=True)
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
Base = declarative_base()
async def get_session() -> AsyncSession:
async with async_session() as session:
yield session
class Country(Base):
__tablename__ = "country"
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
name = Column(String(100), nullable=False)
class President(Base):
__tablename__ = "president"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
country_id = Column(Integer, ForeignKey("country.id"))
country = relationship("Country")
class People(Base):
__tablename__ = "people"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
age = Column(Integer)
country_id = Column(Integer, ForeignKey("country.id"))
country = relationship("Country")
app = FastAPI()
@app.on_event("startup")
async def startup():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
## ULTRA SIMPLE OH MY GOD!
MyMap = RouterMap.create_router_map_from_base(base=Base)
RouterMap.generate(app, get_session)
simply set the extend
parameter to True
then you got the fully extended version
## ULTRA SIMPLE OH MY GOD!
RouterMap.create_router_map_from_base(Base, base_prefix="/v1", extend=True)
RouterMap.generate(app, get_session)
RouterMap
superclassclass MyMap(RouterMap):
country = SimpleRouter(Country)
president = SimpleRouter(President)
people = ExtendedRouter(People)
from fastapi_simple_crud import SimpleCRUDGenerator, RouterMap, SimpleRouter, SimpleEndpoint
## ULTRA SIMPLE OH MY GOD!
class MyPresidentPydantic(BaseModel):
name: int
class MyMap(RouterMap):
country = SimpleRouter(Country, prefix="/v1/country")
president = SimpleRouter(President, prefix="/v1/president",
crud_update=None,
crud_create=SimpleEndpoint(pydantic_model=MyPresidentPydantic),
crud_read=SimpleEndpoint("/custom_read"))
RouterMap.generate(app, get_session)
RouterMap
as a superclassNone
in the SimpleRouter
definition:
crud_create
crud_read
crud_update
crud_delete
disable_crud
(set this to True
this will forcely disable all API generation)MyMap
class) will be generated. From the example, People
router is not exist.SimpleEndpoint()
refers to your HTTP method definition (GET/POST/PUT/DELETE) in the API decorator (ex: @router.get()
, etc.)RouterMap
with ExtendedRouter()
from fastapi_simple_crud import SimpleCRUDGenerator, RouterMap, ExtendedRouter, SimpleEndpoint
## ULTRA SIMPLE OH MY GOD!
class MyPresidentPydantic(BaseModel):
name: int
class MyMap(RouterMap):
country = ExtendedRouter(Country, prefix="/v1/country")
president = ExtendedRouter(President, prefix="/v1/president",
read_one=None,
read_many=SimpleEndpoint("/custom_read")),
update_one=SimpleEndpoint(pydantic_model=MyPresidentPydantic)
RouterMap.generate(app, get_session)
None
in the ExtendedRouter
definition:
create_one
create_many
read_one
read_many
update_one
update_many
delete_one
delete_many
disable_crud
(set this to True
this will forcely disable all API generation)from fastapi import Depends
from sqlalchemy import select
from fastapi_simple_crud import SimpleCRUDGenerator, RouterMap, SimpleRouter, SimpleEndpoint
## ULTRA SIMPLE OH MY GOD!
class MyPresidentPydantic(BaseModel):
name: int
class MyMap(RouterMap):
country = SimpleRouter(Country, prefix="/v1/country", crud_read=None)
president = SimpleRouter(President, prefix="/v1/president")
@MyMap.country.get("/custom_read")
async def get_country(id: int, session: AsyncSession = Depends(get_session)):
query = select(Country).where(Country.id==id)
data = await session.execute(query)
data = data.scalars().first()
return data
RouterMap.generate(app, get_session)
from fastapi_simple_crud import SimpleCRUDGenerator, RouterMap, SimpleRouter, SimpleEndpoint
## ULTRA SIMPLE OH MY GOD!
MyMap = RouterMap.create_router_map_from_base(base=Base)
## you want to remove people from autogeneration
class NewMap(MyMap):
people = SimpleRouter(People, disable_crud=True)
RouterMap.generate(app, get_session)
or inherit from the RouterMap
class NewMap(RouterMap):
people = SimpleRouter(People, disable_crud=True)
or simply update from the RouterMap
people = SimpleRouter(People, disable_crud=True)
RouterMap.update_map(people)
or from the MyMap
MyMap.update_map(people)
You can override ExtendedRouter
with SimpleRouter
and vice versa.
class NewMap(RouterMap):
people = SimpleRouter(People)
class NewMap2(RouterMap):
people = ExtendedRouter(People)
RouterMap.create_router_map_from_base()
from fastapi import Depends
from sqlalchemy import select
from fastapi_simple_crud import SimpleCRUDGenerator, RouterMap, SimpleRouter, SimpleEndpoint
class Country(Base):
__tablename__ = "country"
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
name = Column(String(100), nullable=False)
## ULTRA SIMPLE OH MY GOD!
MyMap = RouterMap.create_router_map_from_base(base=Base)
## use your tablename to get the router attribute from the created router map
## RouterMap in default will automatically mapped your router with its tablename
@MyMap.country.get("/custom_read")
async def get_country(id: int, session: AsyncSession = Depends(get_session)):
query = select(Country).where(Country.id==id)
data = await session.execute(query)
data = data.scalars().first()
return data
RouterMap.generate(app, get_session)
MyMap
)RouterMap
in default will automatically mapped your router with its tablename (in above Country
tablename is country
)class MyMap(RouterMap):
country = SimpleRouter(Country)
president = SimpleRouter(President)
people = ExtendedRouter(People)
## here you go
countryCreateOnePydanticModel = MyMap.country.create_one.pydanticModel
for example we have this class
class People(Base):
__tablename__ = "people"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
age = Column(Integer)
country_id = Column(Integer, ForeignKey("country.id"))
country = relationship("Country")
isAlive = Column(Boolean)
then simply put in to with generate_pydantic_model()
from fastapi import Query
from fastapi_simple_crud.dependencies.utils import generate_pydantic_model
myPeoplePydantic = generate_pydantic_model(People, modelName="myPeoplePydantic")
or with some params..
myPeoplePydantic = generate_pydantic_model(
classModel=People,
modelName="myPeoplePydantic",
exclude_attributes=["id"],
include_attributes_default={"isAlive": True},
include_attributes_paramsType={"isAlive": Query},
)
the code above will generate People
pydantic model without id
attribute
the available params are:
classModel
>> your SQLAlchemy Model Schema ClassmodelName
>> your pydantic model nameexclude_attributes
>> put the attributes you dont want inside your pydanticModel (it will copy all relatied attributes from the SQLAlchemy schema)include_attributes_default
>> set your attributes default paramsinclude_attributes_paramsType
>> set your attributes default paramsuniform_attributes_default
>> override all default value to uniformuniform_attributes_paramsType
>> override all params type to uniform