Skip to content

Commit ca7ef61

Browse files
Added ability to insert a Node instance into an Edge with some options
It's not super clean (lots of duplication) but it works for now and can be cleaned up later.
1 parent fc6a461 commit ca7ef61

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

django_postgresql_dag/models.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
query. These queries also topologically sort the ids by generation.
66
"""
77

8+
from copy import deepcopy
89
from django.apps import apps
910
from django.db import models, connection
1011
from django.db.models import Case, When
@@ -467,6 +468,108 @@ def sort(self, edges, **kwargs):
467468
# ToDo: Implement
468469
pass
469470

471+
def insert_node(self, edge, node, clone_to_rootside=False, clone_to_leafside=False, pre_save=None, post_save=None):
472+
"""
473+
Inserts a node into an existing Edge instance. Returns a tuple of the newly created rootside_edge (parent to
474+
the inserted node) and leafside_edge (child to the inserted node).
475+
476+
Process:
477+
1. Add a new Edge from the parent Node of the current Edge instance to the provided Node instance,
478+
optionally cloning properties of the existing Edge.
479+
2. Add a new Edge from the provided Node instance to the child Node of the current Edge instance,
480+
optionally cloning properties of the existing Edge.
481+
3. Remove the original Edge instance.
482+
483+
The instance will still exist in memory, though not in database
484+
(https://docs.djangoproject.com/en/3.1/ref/models/instances/#refreshing-objects-from-database).
485+
Recommend running the following after conducting the deletion:
486+
`del instancename`
487+
488+
Cloning will fail if a field has unique=True, so a pre_save function can be passed into this method
489+
Likewise, a post_save function can be passed in to rebuild relationships. For instance, if you have a `name`
490+
field that is unique and generated automatically in the model's save() method, you could pass in a the following
491+
`pre_save` function to clear the name prior to saving the new Edge instance(s):
492+
493+
def pre_save(new_edge):
494+
new_edge.name = ""
495+
return new_edge
496+
497+
A more complete example, where we have models named NetworkEdge & NetworkNode, and we want to insert a new
498+
Node (n2) into Edge e1, while copying e1's field properties (except `name`) to the newly created rootside Edge
499+
instance (n1 to n2) is shown below.
500+
501+
Original Final
502+
503+
n1 o n1 o
504+
| \
505+
| o n2
506+
| /
507+
n3 o n3 o
508+
509+
##################################################################################
510+
from myapp.models import NetworkEdge, NetworkNode
511+
512+
n1 = NetworkNode.objects.create(name="n1")
513+
n2 = NetworkNode.objects.create(name="n2")
514+
n3 = NetworkNode.objects.create(name="n3")
515+
516+
# Connect n3 to n1
517+
n1.add_child(n3)
518+
519+
e1 = NetworkEdge.objects.last()
520+
521+
# function to clear the `name` field, which is autogenerated and must be unique
522+
def pre_save(new_edge):
523+
new_edge.name = ""
524+
return new_edge
525+
526+
NetworkEdge.objects.insert_node(e1, n2, clone_to_rootside=True, pre_save=pre_save)
527+
##################################################################################
528+
"""
529+
530+
rootside_edge = None
531+
leafside_edge = None
532+
533+
# Attach the root-side edge
534+
if clone_to_rootside:
535+
rootside_edge = deepcopy(edge)
536+
rootside_edge.pk = None
537+
rootside_edge.parent = edge.parent
538+
rootside_edge.child = node
539+
540+
if callable(pre_save):
541+
rootside_edge = pre_save(rootside_edge)
542+
543+
rootside_edge.save()
544+
545+
if callable(post_save):
546+
rootside_edge = post_save(rootside_edge)
547+
548+
else:
549+
edge.parent.add_child(node)
550+
551+
# Attach the leaf-side edge
552+
if clone_to_leafside:
553+
leafside_edge = deepcopy(edge)
554+
leafside_edge.pk = None
555+
leafside_edge.parent = node
556+
leafside_edge.child = edge.child
557+
558+
if callable(pre_save):
559+
leafside_edge = pre_save(leafside_edge)
560+
561+
leafside_edge.save()
562+
563+
if callable(post_save):
564+
leafside_edge = post_save(leafside_edge)
565+
566+
else:
567+
edge.child.add_parent(node)
568+
569+
# Remove the original edge in the database. Still remains in memory, though, as noted above.
570+
edge.delete()
571+
return rootside_edge, leafside_edge
572+
470573

471574
def edge_factory(
472575
node_model,

0 commit comments

Comments
 (0)