sqlalchemyfastapisqlmodel

Get tree structure from database sqlmodel/fastapi


I have tree structure in database - comments.

class Comment(SQLModel, table=True):
    id: int = Field(primary_key=True, nullable=False, unique=True)
    text: str = Field(nullable=False)
    parent_id: int = Field(nullable=True, foreign_key="comment.id")
    parent: Optional["Comment"] = Relationship(back_populates="children")
    children: Optional[List["Comment"]] = Relationship(
        back_populates="parent", sa_relationship_kwargs={
            "lazy": "joined", "join_depth": 100, "remote_side": "Comment.id"
        }
    )
class CommentSchema(BaseModel):
    id: int
    text: str
    children: Optional["CommentSchema"] = None
    # children: Optional[List["CommentSchema"]] = []

Commented code returns error:

'msg': "Error iterating over object, error: AttributeError: 'Comment' object has no attribute 'pydantic_extra'",

Uncommented code return list:

[
  {
    "id": 2 (child id 2),
    "children": {
      "id": 1 (parent id 1),
    }
  },
  {
    "id": 6 (subchild id 6),
    "children": {
      "id": 2 (child id 2),
      "children": {
        "id": 1(parent id 1),
      }
    }
  },
  {
    "id": 5,
    "children": {
      "id": 2 (child id 2),
      "children": {
        "id": 1 (parent id 1),
      }
    }
  },
  {
    "id": 4 (subchild id 4),
    "children": {
      "id": 2 (child 2),
      "children": {
        "id": 1 (parent id 1),
      }
    }
  },
  {
    "id": 3 (subchild id 3),
    "children": {
      "id": 2 (child id 2),
      "children": {
        "id": 1 (parent id 1),
      }
    }
  },
  {
    "id": 1 (parent id 1),
  }
]

I think it is absolutely clear why I'm not happy with the result. Is there any way to get correct tree structure from database except writting raw sql queries?


Solution

  • First of all:

    schemas.py

    class CommentSchema(BaseModel):
        id: int
        text: str
        children: Optional[List["CommentSchema"]] = []
    

    models.py:

    class Comment(SQLModel, table=True):
        id: int = Field(primary_key=True, nullable=False, unique=True)
        text: str = Field(nullable=False)
        created: datetime = Field(sa_column=Column(DateTime(timezone=True), server_default=func.now()))
        parent_id: int = Field(nullable=True, foreign_key="comment.id")
    
        children: Optional[List["Comment"]] = Relationship(
            sa_relationship_kwargs={
                "lazy": "selectin",
                "join_depth": 100,
                "order_by": "Comment.created.desc()",
                "cascade": "delete",
            },
        )
    

    And it works