自引用表在数据库中是一种比较常见的数据结构,那么在SQLModel中怎么建立一个自引用的数据模型来对应这种数据表呢?主要原理还是参考一对多表结构的数据模型创建方式,在单一模型中建立一对多关系链。

注意:这里需要使用SQLAlchemy中的 remote_site 参数,参见 Relationships API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from typing import Optional

from sqlmodel import Field, Relationship, Session, SQLModel, create_engine


class Node(SQLModel, table=True):
__tablename__ = "node" # 表名

id: Optional[int] = Field(default=None, primary_key=True)
data: str
parent_id: Optional[int] = Field(
foreign_key="node.id", # 这里node为表名
default=None,
nullable=True,
)
parent: Optional["Node"] = Relationship(
back_populates="children",
sa_relationship_kwargs={
"remote_side": "Node.id", # 这里Node为对象名
},
)
children: list["Node"] = Relationship(back_populates="parent")

def test() -> None:
# 建库建表:
sqlite_file_name = "database.db"
sqlite_uri = f"sqlite:///{sqlite_file_name}"
engine = create_engine(sqlite_uri, echo=True)
SQLModel.metadata.drop_all(engine)
SQLModel.metadata.create_all(engine)
session = Session(engine)

# 根节点:
root_node = Node(data="I am root")

# 新建对象时带parent:
node_a = Node(parent=root_node, data="a")
node_b = Node(parent=root_node, data="b")
node_aa = Node(parent=node_a, data="aa")
node_ab = Node(parent=node_a, data="ab")

# 加入上级节点的children列表:
node_ba = Node(data="ba")
node_b.children.append(node_ba)

# 只需要提交root即可:
session.add(root_node)
session.commit()

# 检查项:
assert root_node.children == [node_a, node_b]
assert node_aa.parent.parent.children[1].parent is root_node
assert node_ba.parent.data == "b"
assert all(n.data.startswith("a") for n in node_ab.parent.children)
assert (node_ba.parent.parent.id == node_ba.parent.parent_id == root_node.id)
assert isinstance(root_node.id, int)


if __name__ == "__main__":
test()

来源:https://stackoverflow.com/questions/73420018/how-do-i-construct-a-self-referential-recursive-sqlmodel