LuisLuii / FastAPIQuickCRUD

Generate CRUD methods in FastApi from an SQLAlchemy schema
https://pypi.org/project/fastapi-quickcrud/
MIT License
252 stars 32 forks source link

Suggestion #6

Closed nsankar90 closed 2 years ago

nsankar90 commented 2 years ago

Is it possible to write out all the routers into a python file? Which would be great while we add more end points for the tags

LuisLuii commented 2 years ago

Hi nsankar90, thanks for your suggestion, I have the same plan to build a code gen, but I have no relevant development experience, so it is still in the POC stage. Do you have any implementation suggestions? :)

LuisLuii commented 2 years ago

And you can add a new end point for the tags by tags parameter

from fastapi import FastAPI
from sqlalchemy import *
from sqlalchemy.orm import *
from fastapi_quickcrud.crud_router import generic_sql_crud_router_builder

Base = declarative_base()
class Parent(Base):
    __tablename__ = 'parent_o2o'
    id = Column(Integer, primary_key=True, comment='test-test-test')
    name = Column(String, default='ok', unique = True)
    children = relationship("Child", back_populates="parent")

class Child(Base):
    __tablename__ = 'child_o2o'
    id = Column(Integer, primary_key=True, comment='child_pk_test')
    parent_id = Column(Integer, ForeignKey('parent_o2o.id'), info=({'description': 'child_parent_id_test'}))
    parent = relationship("Parent", back_populates="children")

crud_route_parent = generic_sql_crud_router_builder(
    db_model=Parent,
    prefix="/parent",
    tags=["parent"],
)

crud_route_child = generic_sql_crud_router_builder(
    db_model=Child,
    prefix="/child",
    tags=["child"]
)

app = FastAPI()
[app.include_router(i) for i in [crud_route_parent, crud_route_child]]

@app.get("/", tags=["child"])
async def root():
    return {"message": "Hello World"}

import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8000, debug=False)
LuisLuii commented 2 years ago

Is it possible to write out all the routers into a python file? About this question I may take some time to investigate, since I have also need to convert pedantic model / data classes model to code. Also welcome you PR

In this time, you can use sqlalchemy_to_pydantic() to generate the predefine pedantic model to build you api sqlalchemy_to_pydantic will generate the predesign pydantic model to build the API, you can also use it to build you custom API.

import uvicorn
from fastapi import FastAPI, Depends
from sqlalchemy.orm import declarative_base, sessionmaker

from fastapi_quickcrud import CrudMethods
from fastapi_quickcrud import crud_router_builder
from fastapi_quickcrud import sqlalchemy_to_pydantic
from fastapi_quickcrud.misc.memory_sql import sync_memory_db

app = FastAPI()

Base = declarative_base()
metadata = Base.metadata

from sqlalchemy import CHAR, Column, ForeignKey, Integer, Table
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
metadata = Base.metadata
association_table = Table('association', Base.metadata,
                          Column('left_id', ForeignKey('left.id')),
                          Column('right_id', ForeignKey('right.id'))
                          )

class Parent(Base):
    __tablename__ = 'left'
    id = Column(Integer, primary_key=True)
    children = relationship("Child",
                            secondary=association_table)

class Child(Base):
    __tablename__ = 'right'
    id = Column(Integer, primary_key=True)
    name = Column(CHAR, nullable=True)

user_model_m2m = sqlalchemy_to_pydantic(db_model=association_table,
                                        crud_methods=[
                                            CrudMethods.FIND_MANY,
                                            CrudMethods.UPSERT_ONE,
                                            CrudMethods.UPDATE_MANY,
                                            CrudMethods.DELETE_MANY,
                                            CrudMethods.PATCH_MANY,

                                        ],
                                        exclude_columns=[])

user_model_set = sqlalchemy_to_pydantic(db_model=Parent,
                                        crud_methods=[
                                            CrudMethods.FIND_MANY,
                                            CrudMethods.FIND_ONE,
                                            CrudMethods.CREATE_ONE,
                                            CrudMethods.UPDATE_MANY,
                                            CrudMethods.UPDATE_ONE,
                                            CrudMethods.DELETE_ONE,
                                            CrudMethods.DELETE_MANY,
                                            CrudMethods.PATCH_MANY,

                                        ],
                                        exclude_columns=[])

friend_model_set = sqlalchemy_to_pydantic(db_model=Child,
                                          crud_methods=[
                                              CrudMethods.FIND_MANY,
                                              CrudMethods.UPSERT_MANY,
                                              CrudMethods.UPDATE_MANY,
                                              CrudMethods.DELETE_MANY,
                                              CrudMethods.CREATE_ONE,
                                              CrudMethods.PATCH_MANY,

                                          ],
                                          exclude_columns=[])

crud_route_1 = crud_router_builder(crud_models=user_model_set,
                                   db_model=Parent,
                                   prefix="/Parent",
                                   dependencies=[],
                                   async_mode=True,
                                   tags=["Parent"]
                                   )
crud_route_3 = crud_router_builder(crud_models=user_model_m2m,
                                   db_model=association_table,
                                   prefix="/Parent2child",
                                   dependencies=[],
                                   async_mode=True,
                                   tags=["m2m"]
                                   )
crud_route_2 = crud_router_builder(crud_models=friend_model_set,
                                   db_model=Child,
                                   async_mode=True,
                                   prefix="/Child",
                                   dependencies=[],
                                   tags=["Child"]
                                   )
post_model = friend_model_set.POST[CrudMethods.CREATE_ONE]

sync_memory_db.create_memory_table(Child)
@app.post("/hello",
           status_code=201,
          tags=["Child"],
           response_model=post_model.responseModel,
           dependencies=[])
async def my_api(
        body: post_model.requestBodyModel = Depends(post_model.requestBodyModel),
        session=Depends(sync_memory_db.get_memory_db_session)
):
    db_item = Child(** body.__dict__)
    session.add(db_item)
    session.commit()
    session.refresh(db_item)
    return db_item.__dict__

app.include_router(crud_route_1)
app.include_router(crud_route_2)
app.include_router(crud_route_3)
uvicorn.run(app, host="0.0.0.0", port=8000, debug=False)
nsankar90 commented 2 years ago

Thanks for the quick reply LuisLuii

I tried this sqlalchemy_to_pydantic but I thought that was still in experimental stage. As far as prototyping that is am very much OK with this but I need some additional validation and customisation on each end points, which could not be generalised across endpoints.

I am also working on generating codes so that we could make some quick customisation to land on a desired outcome and consume less memory.

Will update here once I have anything solid.

Thanks again for the time saving repo

LuisLuii commented 2 years ago

I am started for this feature and this issue will be closed, let we discuss in #11

LuisLuii commented 1 year ago

try it LoL