How to add images to models (tables) and save it to database in FastAPI framework?

Viewed 2913

I deal with FastAPI and can't figure out how to make simple (from the point of view of my experience with django) thing - add a product with an image to the database. As I understood it, the image should be stored in a static folder and only a link to it should be stored in the database. Based on the information from the official documentation, I have added this scheme

schema.py

from pydantic import BaseModel, HttpUrl
from typing import Optional


class ProductImageSchema(BaseModel):
    url: HttpUrl
    name: str


class ProductSchema(BaseModel):
    name: str
    description: Optional[str] = None
    image: Optional[ProductImage] = None

I'm using SQLAlchemy. Now the first question I have is how to properly describe the product model. models.py

product = Product(
    "product",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("name", String(50)),
    Column("description", String(50)),
    Column(....str_or_url..????) # field with relation with image,
)

And it is not clear how to create new instances of the product object. Something like...

crud.py

async def post(payload: ProductSchema, file: UploadFile = File(...)):
    content = await file.read()
    if file.content_type not in ['image/jpeg', 'image/png']:
        raise HTTPException(status_code=406, detail="Only .jpeg or .png  files allowed")
    file_name = f'{uuid.uuid4().hex}{ext}'
    async with aiofiles.open(file_name, "wb") as f:
        await f.write(content)
    query = product.insert().values(title=payload.name, description=payload.description, image=????????)
    return await database.execute(query=query)
1 Answers

Your approach is correct. As far as I know, images, as well as other user's files, are stored in a static (or whatever) folder and a reference is kept in the database. In some cases the file name (possibly with the extension) is stored in the table, while in other cases, especially in a more distributed app, the entire URL is stored.

Your crud.py file seems to be correct. Just change the image parameter in the query to either the URL or the filename that you used. Be sure to check that no other user has already inserted a file with the same name (and extension), or you'll overwrite your user's files!

Going back to your questions,

I would further improve the ProductImageSchema in the schema.py file with the following

from datetime import datetime
class ProductImageSchema(BaseModel):
    url: HttpUrl
    name: str
    type: str
    creation_date: datetime.datetime = datetime.now()

Since you haven't specified the data model (i.e. the database structure), I can only infer from what you have written. If my infer is correct, a product may have multiple images, so you'll need a table for the product and one for the images. My guess is that images are not shared between products, otherwise you'll need 3 tables.

Although the piece of code does not look much like valid SQLAlchemy code, here is an example of what you could do

product = Product(
    "product",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("name", String(50)),
    Column("description", String(50))
)
images = Image(
    "image",
    metadata,
    Column("product", Integer, ForeignKey(Product.id), primary_key=True,),
    Column("name", String(50), primary_key=True),
    Column("filetype", String(50))
)

But I'm not sure this is valid SQLAlchemy code since what you posted does not look right as well. Anyways, I hope it is enough to get the idea.

Related