@@ -52,55 +52,136 @@ The main benefits of `ltree`:
5252 python manage.py migrate django_ltree
5353 ```
5454
55- 4 . Alternatively you can avoid install the application, and create the the extensions with a custom migration in an app in your project.
55+ ## Usage
56+ ` django-ltree ` provides a base model class called ` TreeModel ` .
5657
57- ``` python
58- from django.db import migrations
59- from django_ltree.operations import LtreeExtension
58+ ` TreeModel ` does these things out of the box:
6059
61- class Migration (migrations .Migration ):
62- initial = True
63- dependencies = []
60+ * adds a field called ` path ` to your model
61+ * adds ` t_objects ` which is the ` TreeManager ` you can use to work with tree data
62+ * adds two indexes for ` path ` (one ` BTreeIndex ` , one ` GistIndex ` )
63+ * orders items base on ` path `
64+
65+ if you are overriding the ` Meta ` class of your model, you may want to inherit from TreeModel.Meta.
66+
67+ ``` py
68+ class Meta (TreeModel .Meta ):
69+ ```
70+
71+ to keep the indexes and ordering.
6472
65- operations = [LtreeExtension()]
66- ```
6773
6874## Quick Start
6975
70- 1 . Add a PathField to your model :
76+ 1 . inherit from TreeModel :
7177 ``` python
72- from django_ltree.fields import PathField
78+ from django_ltree.models import TreeModel
7379
74- class Category (models . Model ):
80+ class Category (TreeModel ):
7581 name = models.CharField(max_length = 50 )
76- path = PathField()
7782 ```
7883
84+
79852 . Create tree nodes:
8086 ``` python
81- root = Category.objects.create(name = " Root" , path = " root" )
82- child = Category.objects.create(name = " Child" , path = f " { root.path} .child " )
87+ # make an item without a parent (root)
88+ root = Category.t_objects.create(name = " Root" )
89+ # make a child item
90+ child = Category.t_objects.create_child(name = " Child" , parent = root)
91+ # you can also use `add_child` directly on root
92+ child2 = root.add_child(name = " another child" )
8393 ```
8494
95+ note that ` path ` is handled by ` django-ltree ` , you don't need to pass any value for it
96+
85973 . Query ancestors and descendants:
8698 ``` python
8799 # Get all ancestors
88- Category.objects.filter( path__ancestor = child.path )
100+ child.ancestors( )
89101
90102 # Get all descendants
91- Category.objects.filter( path__descendant = root.path )
103+ child.descendants( )
92104 ```
93105
94- ## Migration Dependency
106+ ### TreeModel methods
107+ ` TreeModel ` has the following methods:
108+
109+ 1 . ` label(self) ` : returns the last part of ` path `
110+
111+ 2 . ` ancestors(self) ` : return all the ancestors of the current item
112+
113+ 3 . ` descendants(self) ` : return all the descendants of the current item
114+
115+ 4 . ` parent(self) ` : return the immediate parent of the current item
116+
117+ 5 . ` get_root(self) ` : return the root parent of this item
118+
119+ 6 . ` children(self) ` : return all the immediate children of the current item
120+
121+ 7 . ` siblings(self) ` : return all the siblings of the current item (items that share the same parent with this item)
122+
123+ 8 . ` add_child(self, **kwargs) ` : create a child for this item
124+ kwargs are the arguments used to make the child (the model fields)
125+
126+ 9 . ` change_parent(self, new_parent) ` : change the parent of the current item (this moves the item and all it's descendants to be under another item)
127+ new_parent is either a object of the same model, or the ` path ` value of an object
128+
129+ 10 . ` make_root(self) ` : move the current item to be a root item (moves the item and all it's descendants)
130+
131+ 11 . ` delete(self, cascade=False, **kwargs) ` : deletes the current item
132+ if cascade is True, all the descendants are also deleted, otherwise they will move to become the descendants of the first parent of the deleted item
133+
134+ 12 . ` delete_cascade(self, **kwargs) ` : delete the current item and all it's children
135+
136+
137+ ### TreeManager methods
138+ ` TreeManager ` has the following methods
139+ 1 . ` create_child(self, parent=None, **kwargs) ` : creates an item
140+ if ` parent ` is provided, it will become the parent item of the created item, otherwise creation will happen as root
141+ ` kwargs ` are the model fields used to create the item
142+
143+ 2 . ` create(self, **kwargs) ` : create a root item
144+ ` kwargs ` are the model fields used to create the item
145+
146+ 3 . ` roots(self) ` : return all the root items from database
147+
148+ 4 . ` children(self, path) ` : return all the children of the specified ` path `
149+
150+
151+ ### lookups and functions
152+ for a list of all available operations and functions for ltree check https://www.postgresql.org/docs/current/ltree.html#LTREE-OPS-FUNCS
153+
154+ #### provided lookups:
155+ 1 . ` exact ` (same as ` = ` in postgresql)
156+ ` TreeModel.t_objects.filter(path__exact=path) `
157+
158+ 2 . ` ancestors ` (same as ` @> ` in postgresql)
159+ ` TreeModel.t_objects.filter(path__ancestors=path) `
160+
161+ 3 . ` descendants ` (same as ` <@ ` in postgresql)
162+ ` TreeModel.t_objects.filter(path__descendants=path) `
163+
164+ 4 . ` match ` (same as ` ~ ` in postgresql)
165+ ` TreeModel.t_objects.filter(path__match=f"{self.path}.*{{1}}") `
166+
167+ 5 . ` contains ` (same as ` ? ` in postgresql)
168+ ` TreeModel.t_objects.filter(path__contains="1.*") `
169+
170+ 6 . ` depth ` (calls ` NLEVEL ` function from postgresql)
171+ ` TreeModel.t_objects.filter(path__depth=len(path) + 1) `
172+
173+ #### provided functions
174+ 1 . ` django_ltree.functions.NLevel `
175+ same as NLEVEL function from postgresql
176+
177+ 2 . ` django_ltree.functions.Subpath `
178+ same as ` SUBPATH ` functions from postgresql
179+
180+
181+ for concatenation (` || ` ) you can use ` django.db.models.functions.Concat `
182+
95183
96- Include django_ltree as a dependency in your app's migrations:
97184
98- ``` python
99- class Migration (migrations .Migration ):
100- dependencies = [
101- (" django_ltree" , " __latest__" ),
102- ]
103- ```
104185
105186## Known Issues
106187
0 commit comments