awtkns / fastapi-crudrouter

A dynamic FastAPI router that automatically creates CRUD routes for your models
https://fastapi-crudrouter.awtkns.com
MIT License
1.37k stars 155 forks source link

How to upload a file using fastapi-crudrouter ? #89

Open slamer59 opened 3 years ago

slamer59 commented 3 years ago

Hello, First of all, I am not an expert of FastAPI... so it might not be related at all to fastapi-crudrouter.

I have Pydantic class which holds file metadata:

from pydantic import BaseModel, Field, validator
from fastapi import FastAPI
from fastapi_crudrouter import MemoryCRUDRouter as CRUDRouter

class File(BaseModel):
    FileSize: Optional[ByteSize]
    absolute_path: FilePath

    def __init__(self, *args, **kwargs: Any):
        super().__init__(**kwargs)
        # Size, creationalidator pre
        st = self.absolute_path.stat()
        self.FileSize = st.st_size

    @validator("absolute_path")
    def convert_str_to_path(cls, v, values, **kwargs):
        """Convert string to absolute_path
        Returns:
            Path: Absolute path
        """
        if v is None:
            v = values[0]
        if isinstance(v, str):
            v = Path.path(v)
        return v.resolve()
# Works with local file    
# f = File(absolute_path='somefile.py')

# FastAPI with crudrouter
app = FastAPI()
app.include_router(CRUDRouter(schema=File))

I read the documentation to do something like this but I don't know what to put in CreateFile class ?

class CreateFile(BaseModel):
    pass

app.include_router(CRUDRouter(schema=File, create_schema=CreateFile))

In pure FastAPI, upload is done here:

from fastapi import FastAPI, UploadFile
from fastapi import File as FastFile # To not interfear with hand made class name

@app.post('/')
async def upload_file(file: UploadFile = FastFile(...)):
    with open(f'{file.filename}', 'wb') as buffer:
        shutil.copyfileobj(file.file, buffer)

Any ideas if it is possible and how ?

Maybe with this routing functionality ? https://fastapi-crudrouter.awtkns.com/routing

app = FastAPI()
# class CreateFile(BaseModel):
#     pass
router = CRUDRouter(
    schema=File,
    # create_schema=CreateFile
)

router = CRUDRouter(
    schema=File,
    # create_schema=CreateFile
)

@router.post("/file")
async def upload_file(file: UploadFile = FastFile(...)):
    with open(f"{file.filename}", "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)
    # return ???

app.include_router(router)

Regards

slamer59 commented 3 years ago

The last proposal with router seems to not override the POST method. Any idea ? I don't see an exemple.

slamer59 commented 3 years ago

It's working ! With:

from fastapi.datastructures import UploadFile
from LAPD import Document
from pydantic import BaseModel
from fastapi import FastAPI, UploadFile
from fastapi import File as FastFile
from fastapi_crudrouter import MemoryCRUDRouter as CRUDRouter
from LAPD.core import File
import shutil

app = FastAPI()
router = CRUDRouter(
    schema=File,
)

@router.post("/")
async def upload_file(file: UploadFile = FastFile(...)):
    with open(f"{file.filename}", "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)
    return File(absolute_path=f"{file.filename}")
app.include_router(router)

but why is it working with the path @router.post('') and not @router.post('/file') ?

slamer59 commented 3 years ago

In fact, it is not keep it into memory... Even adding id: int to the attributes.

awtkns commented 2 years ago

Hi @slamer59, sorry for the delayed response. did you manage to get it working?

slamer59 commented 2 years ago

Dont be :) No avance on my side.