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.
- v0.0
- First Upload
- v0.1:
- Added
ExtendedRouter
- Bugs fix
- v0.1.4 :
- using
disable_crud
for bothSimpleRouter()
andExtendedRouter()
(previouslydisable_simple_crud
anddisable_extended_crud
arguments)
- using
- v0.1.5 :
- Auto Generated PydanticModel from both
SimpleRouter()
andExtendedRouter()
be accessed from their object
- Auto Generated PydanticModel from both
- v0.1.6 :
RouterMap.update_map()
can be used to updateExtendedRouter()
- Added
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)
class 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)
- This example show how to use
RouterMap
as a superclass - You could disable the API generation by simply passing between these keyword arguments to
None
in theSimpleRouter
definition:crud_create
crud_read
crud_update
crud_delete
disable_crud
(set this toTrue
this will forcely disable all API generation)
- Only your defined router mapping inside you router map (in above example is
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.)
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)
- You could disable the API generation by simply passing between these keyword arguments to
None
in theExtendedRouter
definition:create_one
create_many
read_one
read_many
update_one
update_many
delete_one
delete_many
disable_crud
(set this toTrue
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)
- You could use your router from the your router map as shown above
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)
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)
- Use your tablename to get the router attribute from the created router map (in above is
MyMap
) RouterMap
in default will automatically mapped your router with its tablename (in aboveCountry
tablename iscountry
)
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