Load Models from JOIN as Dictionary
- GINO version: 1.0.1
- Python version: 3.8.2
- asyncpg version: 0.20.1
Description
The case is simple: a table represents product (each with one brand attribute), pointing at a brand table.
When joining the two tables, I would like to get the brand information in the product, as a dictionary (or JSON, doesn't matter since I'm developing a rest api).
The same case could be applied to product and category, where in this case a many-to-one relationship is used. Instead of having a dictionary representing the category, an array of dictionaries (representing the categories) could be used.
What I Did
products = orm.Product
products = products.join(orm.Brand, orm.Brand.id == orm.Product.brand).select()
if len(category) > 0:
products = products.where(orm.ProductCategory.category.in_(category))
if len(brand) > 0:
products = products.where(orm.Product.brand.in_(brand))
if q != "":
products = products.where(orm.Product.name.like("%" + q + "%"))
products = await products.limit(limit).order_by(orm.Product.name).gino.load(orm.Product.load(brand=orm.Brand.to_dict())).all()
In this case an error is triggered on to_dict() method since it requires the positional argument 'self'
Just returning an attribute is possible as of now (just change to_dict() into an attribute name), but I need the complete information to be JSON serializable (via a dictionary or array of dictionaries) in order to be consumed by a client.
Can this be achieved, in a simple manner, with GINO?
Thanks
How about just orm.Product.load(brand=orm.Brand)? It'll set orm.Brand instances on Product.brand for you.
If you really want to leverage the loader system to serialize the rows directly, you may want to take a look at the CallableLoader and write your own serializer:
subloader = orm.Product.load(brand=orm.Brand)
def serialize(row, context):
product = subloader.do_load(row, context)
return dict(product.to_dict(), brand=product.brand.to_dict())
serialized_products = await query.gino.load(serialize).all()
I didn't test this, but I think it explains the idea.
Thanks for the answer.
In my case, I'm using gino with fastapi, so I'm returning the result as a JSON. With the first method, simply taking the result and converting it does not work
res = [x.to_dict() for x in products]
Gives me an error because orm.Brand is not serializable. to_dict() does not perform a deep conversion to dictionary so that it can be transformed into a serializable object.
I was aware of the loaders, but didn't think they fit my purpose. Will try and let you know.
Thanks