这里说的 AdjacencyList , 就是最常用来在关系数据库中表示树结构的,parent方式:
| id | name | parent | 
|---|---|---|
| 1 | 一 | null | 
| 2 | 二 | 1 | 
| 3 | 三 | 2 | 
上面的数据, 表示的结构就是:
一
  |- 二
    |- 三
模型定义很好做:
| 1 | # -*- coding: utf-8 -*- | 
这里不让parent字段有null, 而使用0代替.
这个例子在关系上, 有一个纠结的地方, 因为 node 这个表, 它是自关联的, 所以如果想要children 和 parent_obj 这两个关系时:
| 1 | children = relationship('Node') | 
呃, 尴尬了.
如果是两个表, 那么 SQLAlchemy 可以通过外键在哪张表这个信息, 来确定关系的方向:
| 1 | class Blog(BaseModel): | 
因为外键在 Blog 中, 所以 Blog -> User 的 user_obj 是一个 N -> 1关系.
反之, User -> Blog 的 blog_list 则是一个 1 -> N 的关系.
而自相关的 Node 无法直接判断方向, 所以 SQLAlchemy 会按 1 -> N 处理, 那么:
| 1 | children = relationship('Node') | 
这两条之中, children 是正确的, 是我们想要的. 要定义 parent_obj 则需要在 relationship 中通过参数明确表示方向:
| 1 | parent_obj = relationship('Node', remote_side=[id]) | 
这种方式就定义了一个, “到 id” 的 N -> 1 关系.
现在完整的模型定义是:
| 1 | class Node(BaseModel): | 
查询方面没什么特殊的了, 不过我发现在自相关的模型关系, lazy 选项不起作用:
| 1 | children = relationship('Node', lazy="joined") | 
都是无效的, 只有在查询时, 手动使用 options() 定义:
| 1 | n = session.query(Node).filter(Node.name==u'一')\ | 
如果要一次查出多级的子节点:
| 1 | n = session.query(Node).filter(Node.name==u'一')\ | 
多个 joinedload() 串连的话, 可以使用 joinedload_all() 来整合:
| 1 | from sqlalchemy.orm import joinedload_all | 
在修改方面, 删除的话, 配置了 cascade , 删除父节点, 则子节点也会自动删除:
| 1 | children = relationship('Node', lazy='joined', cascade='all') # 1 -> N | 
如果只删除子节点, 那么 delete-orphan 选项就很好用了:
| 1 | children = relationship('Node', lazy='joined', cascade='all, delete-orphan') # 1 -> N | 
 
		