@@ -18,8 +18,30 @@ in order to limit the area of the graph to be searched.
18
18
from django.db import models
19
19
from django_postgresql_dag.models import node_factory, edge_factory
20
20
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
+
21
35
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
+ )
23
45
24
46
def __str__(self):
25
47
return self.name
@@ -32,6 +54,14 @@ in order to limit the area of the graph to be searched.
32
54
class NetworkNode(node_factory(NetworkEdge)):
33
55
name = models.CharField(max_length=100)
34
56
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
+
35
65
def __str__(self):
36
66
return self.name
37
67
@@ -68,6 +98,28 @@ in order to limit the area of the graph to be searched.
68
98
>>> b3.add_child(c1)
69
99
>>> b4.add_child(c1)
70
100
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
+
71
123
### Resulting Database Tables
72
124
73
125
#### myapp_networknode
@@ -110,15 +162,6 @@ in order to limit the area of the graph to be searched.
110
162
~/myapp$ python manage.py shell
111
163
>>> from myapp.models import NetworkNode, NetworkEdge
112
164
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
-
122
165
# Descendant methods which return a queryset
123
166
124
167
>>> root.descendants()
@@ -128,15 +171,6 @@ in order to limit the area of the graph to be searched.
128
171
>>> root.descendants_and_self()
129
172
[<NetworkNode: c2>, <NetworkNode: c1>, <NetworkNode: b4>, <NetworkNode: b3>, <NetworkNode: b2>, <NetworkNode: b1>, <NetworkNode: a3>, <NetworkNode: a2>, <NetworkNode: a1>, <NetworkNode: root>]
130
173
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
-
140
174
# Ancestor methods which return a queryset
141
175
142
176
>>> c1.ancestors()
@@ -148,46 +182,61 @@ in order to limit the area of the graph to be searched.
148
182
149
183
# Get the node's clan (all ancestors, self, and all descendants)
150
184
151
- >>> b3.clan_ids()
152
- [1, 4, 7, 9, 10]
153
185
>>> b3.clan()
154
186
<QuerySet [<NetworkNode: root>, <NetworkNode: a3>, <NetworkNode: b3>, <NetworkNode: c1>, <NetworkNode: c2>]>
155
-
187
+
156
188
# Get all roots or leaves associated with the node
157
189
158
- >>> b3.get_roots ()
190
+ >>> b3.roots ()
159
191
{<NetworkNode: root>}
160
- >>> b3.get_leaves ()
192
+ >>> b3.leaves ()
161
193
{<NetworkNode: c1>, <NetworkNode: c2>}
162
194
163
195
# Perform path search
164
196
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)
179
198
<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
181
200
Traceback (most recent call last):
182
201
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
187
206
raise NodeNotReachableException
188
207
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>: {}}}}
191
240
192
241
# Get a queryset of edges relatd to a particular node
193
242
@@ -196,7 +245,7 @@ in order to limit the area of the graph to be searched.
196
245
>>> b4.descendants_edges()
197
246
<QuerySet [<NetworkEdge: b4 c1>]>
198
247
>>> b4.clan_edges()
199
- {< NetworkEdge: b4 c1 >, <NetworkEdge: root a3 >, <NetworkEdge: a3 b4>}
248
+ <QuerySet [< NetworkEdge: root a3 >, <NetworkEdge: a3 b4 >, <NetworkEdge: b4 c1>]>
200
249
201
250
# Get the nodes at the start or end of an edge
202
251
@@ -215,22 +264,24 @@ in order to limit the area of the graph to be searched.
215
264
>>> NetworkEdge.objects.descendants(b3)
216
265
<QuerySet [<NetworkEdge: b3 c2>, <NetworkEdge: b3 c1>]>
217
266
>>> NetworkEdge.objects.ancestors(b3)
218
- <QuerySet [<NetworkEdge: a3 b3 >, <NetworkEdge: root a3 >]>
267
+ <QuerySet [<NetworkEdge: root a3 >, <NetworkEdge: a3 b3 >]>
219
268
>>> NetworkEdge.objects.clan(b3)
220
269
<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)
222
271
<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
224
273
Traceback (most recent call last):
225
274
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
230
281
raise NodeNotReachableException
231
282
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 >]>
234
285
235
286
## ToDo
236
287
0 commit comments