fastapi / sqlmodel

SQL databases in Python, designed for simplicity, compatibility, and robustness.
https://sqlmodel.tiangolo.com/
MIT License
14.14k stars 628 forks source link

Get select with options (selectinload) using response schema #538

Open ProgrammingStore opened 1 year ago

ProgrammingStore commented 1 year ago

First Check

Commit to Help

Example Code

from pydantic import BaseModel

class Parent(SQLModel, table=True):
    id: UUID = sm.Field(UUID, primary_key=True)
    childs:List[Child]= sm.Relationship(
        back_populates="parent"
    )

class Child(SQLModel, table=True):
    parent_id:UUID=sm.Field()
        sa_column=sm.Column(
            sm.ForeignKey("parentr.id")
    )
    parent: "Parent" = sm.Relationship(
        back_populates="childs"
    )

#read schemas

class IChildRead(BaseModel):
    id:UUID

class IParentReadWithChilds(BaseModel):
    childs:List[IChildRead]

Description

What i want to get from pydantic response schema ? I want to get a query with select lazy options, using the schema of response, because this information already contains in relationships of pydantic models. For example: select(Parent).options(selectinload(Parent.Childs)),

The existance of property in pydantic model gives information about the need to use selectinload. Is there any solutions for it?

Operating System

Linux

Operating System Details

any

SQLModel Version

any

Python Version

any

Additional Context

any

cycledriver commented 7 months ago

There are 2 ways to Child load with a selectin (or whatever type of lazy option): 1) Define the lazyload option in your model:

    childs:List[Child]= sm.Relationship(
        back_populates="parent",
        sa_relationship_kwargs: {"lazyload": "selectin"},
    )

Whenever you select Parent objects, the children will always be loaded.

2) At query time

If you want to be a bit more selective about when you do the selectin load, you can add it to the query:

from sqlalchemy.orm import selectinload

all_parents = session.exec(select(Parent).options(selectinload(Parent.childs)).all()

Pretty much anything you can do with the loads is described here:

https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html

Bewinxed commented 4 months ago

There are 2 ways to Child load with a selectin (or whatever type of lazy option):

  1. Define the lazyload option in your model:
    childs:List[Child]= sm.Relationship(
        back_populates="parent",
        sa_relationship_kwargs: {"lazyload": "selectin"},
    )

Whenever you select Parent objects, the children will always be loaded.

  1. At query time

If you want to be a bit more selective about when you do the selectin load, you can add it to the query:

from sqlalchemy.orm import selectinload

all_parents = session.exec(select(Parent).options(selectinload(Parent.childs)).all()

Pretty much anything you can do with the loads is described here:

https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html

Any way to use this without type errors? I'm getting this complaint when I use the selectinload

No overloads for "exec" match the provided argumentsPylance[reportCallIssue](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportCallIssue)
session.py(50, 15): Overload 2 is the closest match
Argument of type "List[PersonaTrait]" cannot be assigned to parameter "keys" of type "_AttrType" in function "selectinload"
  Type "List[PersonaTrait]" is incompatible with type "_AttrType"
    "List[PersonaTrait]" is incompatible with "QueryableAttribute[Any]"
    "List[PersonaTrait]" is incompatible with type "Literal['*']"Pylance[reportArgumentType](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportArgumentType)
Vr3n commented 1 week ago

In version 0.0.21 Passing lazy instead of lazyload worked for me.

 childs:List[Child]= sm.Relationship(
        back_populates="parent",
        sa_relationship_kwargs: {"lazy": "selectin"}, # lazy instead of lazyload
    )