11Usage
22=====
3-
43This section provides practical examples and guidance on using ``fastapi-async-storages ``
54to handle asynchronous file storage in your FastAPI applications.
65
76Working with storages
87---------------------
9-
108Often in projects, you want to get input file in the API and store it somewhere.
119The `fastapi-async-storages ` simplifies the process to store and retrieve the files in a re-usable manner.
1210
@@ -56,7 +54,6 @@ Now let's see a minimal example of using :class:`~async_storages.S3Storage` in a
5654
5755Working with ORM extensions
5856---------------------------
59-
6057The example you saw was useful, but **fastapi-async-storages ** has ORM integrations
6158which makes storing and serving the files easier.
6259
@@ -67,7 +64,6 @@ Support ORM include:
6764
6865SQLAlchemy
6966~~~~~~~~~~
70-
7167You can use custom :code: `SQLAlchemy ` types from :code: `fastapi-async-storages ` for this.
7268
7369Supported types include:
@@ -101,32 +97,71 @@ Let's see an example:
10197 )
10298
10399 class Document (Base ):
104- __tablename__ = " documents"
100+ __tablename__ = " documents"
105101
106- id = Column(Integer, primary_key = True )
107- file = Column(FileType(storage = storage))
108- image = Column(ImageType(storage = storage))
102+ id = Column(Integer, primary_key = True )
103+ file = Column(FileType(storage = storage))
104+ image = Column(ImageType(storage = storage))
109105
110106 async def main ():
111107 async with engine.begin() as conn:
112108 await conn.run_sync(Base.metadata.create_all)
113109
114- # create an in-memory image
115- img_buf = BytesIO()
116- Image.new(" RGB" , (32 , 16 ), color = (255 , 0 , 0 )).save(img_buf, format = " PNG" )
117- img_buf.seek(0 )
118-
119- # upload and link file and image
120- img_name await storage.upload(img_buf, " uploads/test-image.png" )
121- file_name = await storage.upload(BytesIO(b " hello world" ), " uploads/test.txt" )
122-
123- async with async_session() as session:
124- doc = Document(file = file_name, image = img_name)
125- session.add(doc)
126- await session.commit()
127-
128- doc = await session.get(Document, doc.id)
129- url = await doc.file.get_path()
130- print (url)
131- width, height = await doc.image.get_dimensions()
132- print (f " Dimensions: { width} x { height} " )
110+ # create an in-memory image
111+ img_buf = BytesIO()
112+ Image.new(" RGB" , (32 , 16 ), color = (255 , 0 , 0 )).save(img_buf, format = " PNG" )
113+ img_buf.seek(0 )
114+
115+ # upload and link file and image
116+ img_name await storage.upload(img_buf, " uploads/test-image.png" )
117+ file_name = await storage.upload(BytesIO(b " hello world" ), " uploads/test.txt" )
118+
119+ async with async_session() as session:
120+ doc = Document(file = file_name, image = img_name)
121+ session.add(doc)
122+ await session.commit()
123+
124+ doc = await session.get(Document, doc.id)
125+ url = await doc.file.get_path()
126+ print (url)
127+ width, height = await doc.image.get_dimensions()
128+ print (f " Dimensions: { width} x { height} " )
129+
130+ Integration with `Alembic <https://alembic.sqlalchemy.org/en/latest/ >`_
131+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
132+ By default, custom types are not registered in Alembic's migrations.
133+ To integrate these new types with Alembic, you can do this:
134+
135+ We create the following snippet in ``custom_types.py ``:
136+
137+ .. code-block :: python
138+
139+ from typing import Any
140+ from async_storages.integrations.sqlalchemy import FileType as _FileType
141+
142+ from app.core.storages import storage
143+
144+ class FileType (_FileType ):
145+ def __init__ (self , * args : Any, ** kwargs : Any):
146+ super ().__init__ (storage = storage, * args, ** kwargs)
147+
148+ And by using the new :class: `~async_storages.integrations.sqlalchemy.FileType ` Alembic can do the imports properly.
149+
150+ Add files path to ``script.py.mako ``.
151+ Alembic allows you to modify ``script.py.mako `` and the migrations are generated with proper imports.
152+
153+ .. code-block :: mako
154+
155+ """${message}
156+
157+ Revision ID: ${up_revision}
158+ Revises: ${down_revision | comma,n}
159+ Create Date: ${create_date}
160+
161+ """
162+ from alembic import op
163+ import sqlalchemy as sa
164+ import path_to_custom_types_py_file
165+ ${imports if imports else ""}
166+
167+ # THE REST OF SCRIPT
0 commit comments