django-treebeard
소개계층 구조를 표현하는 방법은 크게 네가지가 있다.
앞선 Post에서 각각의 방법에 대한 Django Model, 부모/자식 노드 판별, SubTree를 구하는 예시에 대해 설명했다.
하지만, production에서 사용하기 위해서 상황마다 노드를 추가/삭제하는 방법에 대해 고민해야하고, Tree Manager
class를 구현해서 사용하기 쉬운 메소드를 제공해야한다. 이는 쉬운 일이 아니고, 계층 구조를 프로젝트에 적용하기 어렵다.
django-treebeard
는 Adjaceny List without CTE
, Materialized Path
, Nested Set
을 쉽게 사용할 수 있도록, 각각의 Node Model과 NodeManager
, TreeManager
를 제공한다. wagtail
이나 django-cms
같은 django기반 오픈 소스들에서 계층 구조를 표현하기 위한 라이브러리로 django-treebeard
를 사용하고 있다.
계층 구조를 설계하는 가장 기본은 Adjaceny List
이다. 제공되는 모델 중에서 유일하게 정규화된 형태이고, 데이터의 정합성이 구조적으로 보장되기 때문이다. Depth 정보, Sibling Node의 순서, Traversing 성능이 중요한 경우 다른 모델을 고려해보는 것이 좋다.
Depth정보, Sibling Node의 순서, 간단한 쿼리 작성이 필요한 경우 Materialized Path
모델을 선택하는 것이 좋다. 특히 Descendants Node를 조회하는 쿼리는 Leaf Node의 depth를 모르더라도, Self Join이 필요없는 Sargable Query
라는 점이 특징적이다. 그러나 CHAR형태인path
로 노드 사이의 관계를 정의하므로 Node의 갯수에 제한이 있다. 또한, Ascendants를 조회하는 쿼리는 IN
operator를 요구하고 sargable하지는 않다.
변경이 자주 없고 Traversing 성능이 중요한 경우 Nested Set
모델이 유리하다. descendant, ascendant 모두 간단한 sargable query로 조회할 수 있고, 노드의 갯수에 제한이 없다는 것이 장점이다. 그러나, 노드의 추가 삭제가 발생하는 경우 전체 노드에 대해 조회하고 수정하는 경우가 생기므로 cost가 크다.
django-treebeard
제공 APIadd_root(self: Node,**kwargs) -> None
add_child(self: Node,**kwargs) -> None
add_sibling(self: Node, pos: int=None, **kwargs) -> None
move(target: Node, pos: int=None) -> None
get_tree(self: Node, parent: Node=None) -> QuerySet[Node]