Skip to content

Relationship attribute not in model schema #255

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

Closed
8 tasks done
carlosporta opened this issue Feb 28, 2022 · 6 comments
Closed
8 tasks done

Relationship attribute not in model schema #255

carlosporta opened this issue Feb 28, 2022 · 6 comments
Labels
answered question Further information is requested

Comments

@carlosporta
Copy link

First 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

from fastapi import FastAPI
from sqlmodel import Field, Relationship, SQLModel, create_engine, Session, select


class Child(SQLModel, table=True):
    __tablename__ = "child"
    id: int = Field(default=None, primary_key=True)
    parent_id: int = Field(default=None, foreign_key="parent.id")
    parent: "Parent" = Relationship(back_populates="children")


class Parent(SQLModel, table=True):
    __tablename__ = "parent"
    id: int = Field(default=None, primary_key=True)
    children: List[Child] = Relationship(
        back_populates="parent",
        sa_relationship_kwargs={"lazy": "joined"},
    )


engine = create_engine("sqlite:///./test.db", connect_args={'check_same_thread': False})
SQLModel.metadata.drop_all(engine)
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
    session.add(Parent(id=0))
    session.add(Child(id=0, parent_id=0))
    session.add(Child(id=1, parent_id=0))
    session.commit()


app = FastAPI()
@app.get("/parent", response_model=Parent)
def get_parent():
    with Session(engine) as session:
        parent = session.exec(select(Parent)).first()
        print(parent)
        # id=0 children=[Child(parent_id=0, id=0), Child(parent_id=0, id=1)]
        return parent


print(Parent.schema())
# {'title': 'Parent', 'type': 'object', 'properties': {'id': {'title': 'Id', 'type': 'integer'}}}
# Repare that there is no children attribute

Description

I have two related models (one parent to many children). And that relationship is eager, as you can see when I select a parent and print it, it is possible to see its children too. But the problem happens when I want to cast the result from the select statement to a parent model, using for example the from_orm function, because there is no attribute named children on the parent schema. My problem is probably related to this issue: #224.

Operating System

Windows

Operating System Details

No response

SQLModel Version

0.0.6

Python Version

3.10.2

Additional Context

No response

@carlosporta carlosporta added the question Further information is requested label Feb 28, 2022
@4linuxfun
Copy link

4linuxfun commented Mar 21, 2022

I think it's useful,you can see the doc :https://sqlmodel.tiangolo.com/tutorial/fastapi/relationships/

@AdamMisiak
Copy link

Hey @carlosporta!
I am facing very similar issue right now. Did you manage to solve this? :)

@alp09
Copy link

alp09 commented Jun 9, 2022

@AdamMisiak
I had a problem where relationship attributes would not appear at all. Aparently SQLAlchemy 1.4.36 (current version is 1.4.37) breaks relationships (source).

I installed version 1.4.35 and it fixed my issue, hope it fixes yours too!

@kiddten
Copy link

kiddten commented Jun 20, 2022

same issue here

@tiangolo
Copy link
Member

Hey there @carlosporta! You need to declare a model that explicitly includes the children for the response_model, otherwise you could end up with infinite recursion.

As @4linuxfun says, you can read the docs explaining it, the relevant section is here: https://sqlmodel.tiangolo.com/tutorial/fastapi/relationships/#dont-include-all-the-data


About the issue mentioned by @alp09, that one is reported here: #315, it was solved here: #322, it will be available in the next version, in a couple of hours, SQLModel 0.0.7.

@koldakov
Copy link

@tiangolo

  1. I'm using sqlmodel to reduce mappings between sqlalchemy models/pydantic models
  2. I can't use response_model as I'm using template responses and need to model dump to context ( aka problem 1 )

Currently what I did is:

from sqlmodel import SQLModel as _SQLModel

class SQLModel(_SQLModel):
    """Base Model Class."""

    def model_dump(self, ...):
        ""Some magic happens here""

Also there is a method I've written for pagination that is available for table=True objects, which returns Page[SQLModel], so there is no way of mapping WhateverModel to WhateverModelWithRelations without extra magic

So as you understand that's not the ideal solution.

Also I've looked into the code and as I understand you don't add Relation fields as real fields that's why it doesn't work, but in fact there is no need to load relations by default cause it leads to the extra DB requests, so maybe it does make sense to limit recursion level ( for example, as it's done in sqlalchemy - recursion_depth )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
answered question Further information is requested
Projects
None yet
Development

No branches or pull requests

7 participants