Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load Models from JOIN as Dictionary #724

Open
lsabi opened this issue Sep 15, 2020 · 2 comments
Open

Load Models from JOIN as Dictionary #724

lsabi opened this issue Sep 15, 2020 · 2 comments
Labels
question A community question, closed when inactive.

Comments

@lsabi
Copy link

lsabi commented Sep 15, 2020

  • 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

@fantix
Copy link
Member

fantix commented Sep 25, 2020

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.

@fantix fantix added the question A community question, closed when inactive. label Sep 25, 2020
@lsabi
Copy link
Author

lsabi commented Sep 25, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question A community question, closed when inactive.
Projects
None yet
Development

No branches or pull requests

2 participants