@@ -18,8 +18,30 @@ in order to limit the area of the graph to be searched.
1818 from django.db import models
1919 from django_postgresql_dag.models import node_factory, edge_factory
2020
21+ class EdgeSet(models.Model):
22+ name = models.CharField(max_length=100, unique=True)
23+
24+ def __str__(self):
25+ return self.name
26+
27+
28+ class NodeSet(models.Model):
29+ name = models.CharField(max_length=100, unique=True)
30+
31+ def __str__(self):
32+ return self.name
33+
34+
2135 class NetworkEdge(edge_factory("NetworkNode", concrete=False)):
22- name = models.CharField(max_length=100)
36+ name = models.CharField(max_length=100, unique=True)
37+
38+ edge_set = models.ForeignKey(
39+ EdgeSet,
40+ on_delete=models.CASCADE,
41+ null=True,
42+ blank=True,
43+ related_name="edge_set_edges",
44+ )
2345
2446 def __str__(self):
2547 return self.name
@@ -32,6 +54,14 @@ in order to limit the area of the graph to be searched.
3254 class NetworkNode(node_factory(NetworkEdge)):
3355 name = models.CharField(max_length=100)
3456
57+ node_set = models.ForeignKey(
58+ NodeSet,
59+ on_delete=models.CASCADE,
60+ null=True,
61+ blank=True,
62+ related_name="node_set_nodes",
63+ )
64+
3565 def __str__(self):
3666 return self.name
3767
@@ -68,6 +98,28 @@ in order to limit the area of the graph to be searched.
6898 >>> b3.add_child(c1)
6999 >>> b4.add_child(c1)
70100
101+ ### Add Edges and Nodes to EdgeSet and NodeSet models (FK)
102+
103+ >>> y = EdgeSet.objects.create()
104+ >>> y.save()
105+
106+ >>> c1_ancestors = c1.ancestors_edges()
107+
108+ >>> for ancestor in c1_ancestors:
109+ >>> ancestor.edge_set = y
110+ >>> ancestor.save()
111+
112+ >>> x = NodeSet.objects.create()
113+ >>> x.save()
114+ >>> root.node_set = x
115+ >>> root.save()
116+ >>> a1.node_set = x
117+ >>> a1.save()
118+ >>> b1.node_set = x
119+ >>> b1.save()
120+ >>> b2.node_set = x
121+ >>> b2.save()
122+
71123### Resulting Database Tables
72124
73125#### myapp_networknode
@@ -110,15 +162,6 @@ in order to limit the area of the graph to be searched.
110162 ~/myapp$ python manage.py shell
111163 >>> from myapp.models import NetworkNode, NetworkEdge
112164
113- # Descendant methods which return ids
114-
115- >>> root.descendants_ids()
116- [2, 3, 4, 5, 6, 7, 8, 9, 10]
117- >>> root.self_and_descendants_ids()
118- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
119- >>> root.descendants_and_self_ids()
120- [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
121-
122165 # Descendant methods which return a queryset
123166
124167 >>> root.descendants()
@@ -128,15 +171,6 @@ in order to limit the area of the graph to be searched.
128171 >>> root.descendants_and_self()
129172 [<NetworkNode: c2>, <NetworkNode: c1>, <NetworkNode: b4>, <NetworkNode: b3>, <NetworkNode: b2>, <NetworkNode: b1>, <NetworkNode: a3>, <NetworkNode: a2>, <NetworkNode: a1>, <NetworkNode: root>]
130173
131- # Ancestor methods which return ids
132-
133- >>> c1.ancestors_ids()
134- [1, 4, 7, 8]
135- >>> c1.ancestors_and_self_ids()
136- [1, 4, 7, 8, 9]
137- >>> c1.self_and_ancestors_ids()
138- [9, 8, 7, 4, 1]
139-
140174 # Ancestor methods which return a queryset
141175
142176 >>> c1.ancestors()
@@ -148,46 +182,61 @@ in order to limit the area of the graph to be searched.
148182
149183 # Get the node's clan (all ancestors, self, and all descendants)
150184
151- >>> b3.clan_ids()
152- [1, 4, 7, 9, 10]
153185 >>> b3.clan()
154186 <QuerySet [<NetworkNode: root>, <NetworkNode: a3>, <NetworkNode: b3>, <NetworkNode: c1>, <NetworkNode: c2>]>
155-
187+
156188 # Get all roots or leaves associated with the node
157189
158- >>> b3.get_roots ()
190+ >>> b3.roots ()
159191 {<NetworkNode: root>}
160- >>> b3.get_leaves ()
192+ >>> b3.leaves ()
161193 {<NetworkNode: c1>, <NetworkNode: c2>}
162194
163195 # Perform path search
164196
165- >>> root.path_ids_list(c1)
166- [[1, 4, 7, 9]]
167- >>> c1.path_ids_list(root)
168- Traceback (most recent call last):
169- File "<input>", line 1, in <module>
170- c1.path_ids_list(root)
171- File "/home/runner/pgdagtest/pg/models.py", line 313, in path_ids_list
172- raise NodeNotReachableException
173- pg.models.NodeNotReachableException
174- >>> c1.path_ids_list(root, directional=False)
175- [[1, 4, 7, 9]]
176- >>> root.path_ids_list(c1, max_paths=2)
177- [[1, 4, 7, 9], [1, 4, 8, 9]]
178- >>> root.shortest_path(c1)
197+ >>> root.path(c1)
179198 <QuerySet [<NetworkNode: root>, <NetworkNode: a3>, <NetworkNode: b3>, <NetworkNode: c1>]>
180- >>> c1.shortest_path (root)
199+ >>> c1.path (root) # Path defaults to top-down search, unless `directional` is set to False
181200 Traceback (most recent call last):
182201 File "<input>", line 1, in <module>
183- c1.shortest_path (root)
184- File "/home/runner/pgdagtest/pg/models.py", line 323 , in shortest_path
185- return self.filter_order_ids( self.path_ids_list (target_node, directional=directional)[0])
186- File "/home/runner/pgdagtest/pg/models.py", line 313 , in path_ids_list
202+ c1.path (root)
203+ File "/home/runner/pgdagtest/pg/models.py", line 548 , in path
204+ ids = [item.id for item in self.path_raw (target_node, **kwargs)]
205+ File "/home/runner/pgdagtest/pg/models.py", line 544 , in path_raw
187206 raise NodeNotReachableException
188207 pg.models.NodeNotReachableException
189- >>> c1.shortest_path(root, directional=False)
190- <QuerySet [<NetworkNode: root>, <NetworkNode: a3>, <NetworkNode: b4>, <NetworkNode: c1>]>
208+ >>> c1.path(root, directional=False)
209+ <QuerySet [<NetworkNode: c1>, <NetworkNode: b3>, <NetworkNode: a3>, <NetworkNode: root>]>
210+ >>> root.distance(c1)
211+ 3
212+
213+ # Check node properties
214+
215+ >>> root.is_root()
216+ True
217+ >>> root.is_leaf()
218+ False
219+ >>> root.is_island()
220+ False
221+ >>> c1.is_root()
222+ False
223+ >>> c1.is_leaf()
224+ True
225+ >>> c1.is_island()
226+ False
227+
228+ # Get ancestors/descendants tree output
229+
230+ >>> a2.descendants_tree()
231+ {<NetworkNode: b2>: {}}
232+ >>> root.descendants_tree()
233+ {<NetworkNode: a1>: {<NetworkNode: b1>: {}, <NetworkNode: b2>: {}}, <NetworkNode: a2>: {<NetworkNode: b2>: {}}, <NetworkNode: a3>: {<NetworkNode: b3>: {<NetworkNode: c2>: {}, <NetworkNode: c1>: {}}, <NetworkNode: b4>: <NetworkNode: c1>: {}}}}
234+ >>> root.ancestors_tree()
235+ {}
236+ >>> c1.ancestors_tree()
237+ {<NetworkNode: b3>: {<NetworkNode: a3>: {<NetworkNode: root>: {}}}, <NetworkNode: b4>: {<NetworkNode: a3>: {<NetworkNode: root>: {}}}}
238+ >>> c2.ancestors_tree()
239+ {<NetworkNode: b3>: {<NetworkNode: a3>: {<NetworkNode: root>: {}}}}
191240
192241 # Get a queryset of edges relatd to a particular node
193242
@@ -196,7 +245,7 @@ in order to limit the area of the graph to be searched.
196245 >>> b4.descendants_edges()
197246 <QuerySet [<NetworkEdge: b4 c1>]>
198247 >>> b4.clan_edges()
199- {< NetworkEdge: b4 c1 >, <NetworkEdge: root a3 >, <NetworkEdge: a3 b4>}
248+ <QuerySet [< NetworkEdge: root a3 >, <NetworkEdge: a3 b4 >, <NetworkEdge: b4 c1>]>
200249
201250 # Get the nodes at the start or end of an edge
202251
@@ -215,22 +264,24 @@ in order to limit the area of the graph to be searched.
215264 >>> NetworkEdge.objects.descendants(b3)
216265 <QuerySet [<NetworkEdge: b3 c2>, <NetworkEdge: b3 c1>]>
217266 >>> NetworkEdge.objects.ancestors(b3)
218- <QuerySet [<NetworkEdge: a3 b3 >, <NetworkEdge: root a3 >]>
267+ <QuerySet [<NetworkEdge: root a3 >, <NetworkEdge: a3 b3 >]>
219268 >>> NetworkEdge.objects.clan(b3)
220269 <QuerySet [<NetworkEdge: root a3>, <NetworkEdge: a3 b3>, <NetworkEdge: b3 c2>, <NetworkEdge: b3 c1>]>
221- >>> NetworkEdge.objects.shortest_path (root, c1)
270+ >>> NetworkEdge.objects.path (root, c1)
222271 <QuerySet [<NetworkEdge: root a3>, <NetworkEdge: a3 b3>, <NetworkEdge: b3 c1>]>
223- >>> NetworkEdge.objects.shortest_path (c1, root)
272+ >>> NetworkEdge.objects.path (c1, root) # Path defaults to top-down search, unless `directional` is set to False
224273 Traceback (most recent call last):
225274 File "<input>", line 1, in <module>
226- NetworkEdge.objects.shortest_path(c1, root)
227- File "/home/runner/pgdagtest/pg/models.py", line 425, in shortest_path
228- self.model.objects, ["parent_id", "child_id"], start_node.path_ids_list(end_node)[0]
229- File "/home/runner/pgdagtest/pg/models.py", line 313, in path_ids_list
275+ NetworkEdge.objects.path(c1, root)
276+ File "/home/runner/pgdagtest/pg/models.py", line 677, in path
277+ start_node.path(end_node),
278+ File "/home/runner/pgdagtest/pg/models.py", line 548, in path
279+ ids = [item.id for item in self.path_raw(target_node, **kwargs)]
280+ File "/home/runner/pgdagtest/pg/models.py", line 544, in path_raw
230281 raise NodeNotReachableException
231282 pg.models.NodeNotReachableException
232- >>> NetworkEdge.objects.shortest_path (c1, root, directional=False)
233- <QuerySet [<NetworkEdge: root a3 >, <NetworkEdge: a3 b4 >, <NetworkEdge: b4 c1 >]>
283+ >>> NetworkEdge.objects.path (c1, root, directional=False)
284+ <QuerySet [<NetworkEdge: b3 c1 >, <NetworkEdge: a3 b3 >, <NetworkEdge: root a3 >]>
234285
235286## ToDo
236287
0 commit comments