SQLAlchemy 1.4 table query that includes first result of second table

Viewed 19

Good day,

I'm using SQLAlchemy 1.4 and have two tables, one is a table for Widget and the second is an Image table. Currently, I query for the widget then once found I query for the most recent image for that given widget so I return an API response that includes the widget information plus one image of the widget.

As a simple optimization step I added a cache when fetching the single image of each widget but that was only a temporary stop-gap and I know there must be a way to load the most recent image of the widget at the same time I request the widget.

I found some examples of using .scalar_subquery() which I believe can fit my needs but the examples were a bit shallow in context and I didn't manage to apply the patterns from those examples to my code base.

Here is what my get_by_id method looks like for reference. self_table is the Widget ORM table.

async def _get_one(self, item_id: UUID):
        query = (
            select(self._table)
            .options(selectinload(self._table.things))
            .where(self._table.id == item_id)
        )
        try:
            item = (await self._db_session.execute(query)).scalar_one()
        except NoResultFound:
            item = None
        return item

Where things are a many to many table that I load with the widget so I don't make two SQL calls for each widget API request. Adding things to the widget like this is easy since I load all things on the many-to-many relationship without any constraints. But as described above, I do want to constrain the images I load and this is where I have found it difficult.

Ideally, I would fetch the most recent image from the Image table which has a foreign key on the widget ID and if more images are needed then the user can fetch all images of the widget to load them separately.


Alternatively, I could add an image_id column to the Widget table then with zero extra work return the Widget item and allow the client to fetch the the Image if they have not already cached the Image already. Not sure if this is more common approach or not. Making a query for both the widget and image in each endpoint or for various points of the app has me handling both objects which is not really ideal either.

So maybe I have my ideal solution wrong and really there may be a way to define a sa.relationship that only returns the first Image row whenever I query for a Widget?

Thank you

0 Answers
Related