Selectin for the SQLModels relations
See original GitHub issueFirst Check
- I added a very descriptive title to this issue.
- I used the GitHub search to find a similar issue and didn’t find it.
- I searched the SQLModel documentation, with the integrated search.
- I already searched in Google “How to X in SQLModel” and didn’t find any information.
- I already read and followed all the tutorial in the docs and didn’t find an answer.
- I already checked if it is not related to SQLModel but to Pydantic.
- I already checked if it is not related to SQLModel but to SQLAlchemy.
Commit to Help
- I commit to help with one of those options 👆
Example Code
class Team(SQLModel):
id: int = Field(default=None, primary_key=True)
heroes: List["Hero"] = Relationship(back_populates="team", sa_relationship_kwargs={"lazy": "selectin"})
class Hero(SQLModel):
name: str
team_id: Optional[int] = Field(default=None, foreign_key="team.id")
team: Optional[Team] = Relationship(back_populates="incidents")
app = FastAPI()
@app.get("/teams/", response_model=List[Team])
def get_teams() -> List[Team]:
with Session(engine) as session:
return session.exec(select(Team)).all()
desired_output = [
{
"id": 1,
"heroes": [
{"name": "Batman"},
{"name": "Superman"}
]
}
]
Description
When returning a list of Teams the Relationship
fields are not covered in the output. I believe the response is using pydantic.main.BaseModel.json()
to get the data (and there it will only cover non-Relationship
fields).
It would be great if there was an option to also return the Relationship
fields especially if {"lazy": "selectin"}
was enabled for the relation.
It’s an easy workaround to walk the objects and return the complete data as json in the endpoint, but since we already have the models that is not very satisfying (also because the response_model for openapi will not be easily achievable).
Did I miss an option to enable having the Relationship
attributes in the response, or is that something that could be worked on?
I would also be happy to contribute but would need a pointer on where to start.
Operating System
Linux
Operating System Details
No response
SQLModel Version
0.0.7
Python Version
3.10.4
Additional Context
No response
Issue Analytics
- State:
- Created a year ago
- Comments:6
Does anyone have the models separated in different files? When I separate the Hero from the Team in two different files I get an error when open “/docs/”
In one file all is running ok, but not with separated files. All is running OK with separated files, without the HeroReadWithTeam / TeamReadWithHeroes
Note: I’m using TYPE_CHECKING with imports.
First off, if you haven’t already, I suggest reading this section of the docs. It addresses the issue of infinite recursion (among other things) that can easily happen, if you don’t think carefully about what data you actually want to get.
Second, I assume you forgot to copy the
table=True
in your example models. Without those, you can’t use the models for any database queries.The cyclic dilemma
There are already quite a few issues around this topic of including relationships in such a way. I haven’t looked deeply into the code for this yet. But as I understand it, it is not at all clear, how exactly you should tackle the problem of cyclical relationship graphs. Not that there aren’t any theoretical solutions. It seems to be more of a question of what a “sensible” approach may look like. In the end, it would have to be up to the user to decide, when exactly to stop walking along the relationship graph.
The most straightforward solution, and the one used right now is to simply avoid the issue altogether and force the user to e.g. set up his own response models (not tables) with the desired nesting of sub-models. (See the section “What Data to Include” on the aforementioned docs page.)
Be explicit yourself
So I would suggest closely following the advice about model inheritance from the docs for now. That means for your desired output:
Under the hood, FastAPI will basically call the
TeamReadWithHeroes.from_orm()
method on eachTeam
instance returned by the database query. This will populate theheroes
field on that model and give you the desired result: