-
Notifications
You must be signed in to change notification settings - Fork 143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add NodeGroup.grouping_node
#11613
#11614
Conversation
Node.nodegroup_root
#11613Node.grouping_node
#11613
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall lgtm 🚀 ! One question in the body of code.
On a more meta note, if it's possible to add the Node
relation to NodeGroup
instead of this change and still power what you're trying to do I think there'd be an additional win gained there. There have been quite a few times I've needed to get the node from the nodegroup and end up running to the db again 💀
If that can't be accommodated, how do you feel about changing grouping_node
to nodegroup_node
? idk grouping_node
isn't really referenced elsewhere in code and IMO it's more descriptive to say what the thing actually is.
Thanks for taking a look. I'm going to pump the brakes for a couple days since I just got a few 👍 's on Slack for the idea of just factoring out a subquery into a queryset method. If you have to remember
I first had |
Cool cool! One thing re slack convo: And ++ for having the same thoughts about naming. Hopefully that makes it in 🤞 |
Yeah I think if we want other stuff from the node then it should go back to an FK, but I can definitely explore putting the column on the nodegroup. I'll give it some thought. |
I don't have a strong opinion on this. My preference is |
Also, |
I gave it some thought, and although it makes intuitive sense to put it on NodeGroup, I think there are some considerations going the other way:
This is actually my main motivation, and now there's a way to do that when fetching the data. On the other proposal (column on NodeGroup) you'd have to select_related() the grouping node when fetching data, so it's not like the developer gets a permission slip to not think about this ;) # Make sure to get grouping nodes before you need them
In [49]: with_grouping_nodes = NodeGroup.objects.filter(node__gt=0).prefetch_related('node_set__grouping_node').distinct()
In [50]: for ng in with_grouping_nodes:
...: print(ng.node_set.all()[0].grouping_node.alias) |
I agree with @chiatt. I think |
I would also say that from a "what makes the most sense" perspective (and not to throw a monkey wrench 🐵 🔧 into this discussion) that having this on the "Nodegroup" table makes the most sense. So, in that case you'd end with something like this Now pragmatically speaking this may not net us less db calls if that's what we're trying to achieve with this, but it does feel very natural. |
Node.grouping_node
#11613NodeGroup.root_node
#11613
Yeah, it makes good sense to move it. I can handle the missing safety with a Django system check. |
@chiatt ready for another look :-) |
198ca98
to
0f23a6c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm OOO today but saw these interesting updates and wanted to stick my nose in 👃
arches/app/models/migrations/11613_nodegroup_root_node_constraints.py
Outdated
Show resolved
Hide resolved
NodeGroup.root_node
#11613NodeGroup.grouping_node
#11613
f9cd0c7
to
b6ec097
Compare
fa8c795
to
a569d6b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking good, just a few questions 👍
constraints = [ | ||
models.CheckConstraint( | ||
condition=Q(grouping_node=models.F("pk")) | ||
| Q(grouping_node__isnull=True), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry to potentially rehash but it's been a bit since I've looked at this. What's the condition for a NodeGroup to exist without a Node?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Purely for convenience when creating them -- we have to create one (NodeGroup) and then the other (Node), unless we want to require that everybody create them in a single transaction and then run this as a deferred constraint, but that's a breaking change I didn't want to impose.
There's a validation check in manage.py validate that checks for nodeless nodegroups. Apparently we're still creating some on setup_db:
Arches integrity report
Prepared by Arches 8.0.0a0 on Thu Jan 2 15:41:29 2025
Error Rows Fixable? Description
PASS 1005 0 N/A Nodes with ontologies found in graphs without ontologies
FAIL 1012 1 Yes Node Groups without contained nodes
PASS 1013 0 N/A Node Groups without a grouping node
PASS 1014 0 N/A Publication missing for language
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I keep getting the following error when attempting to open an existing model in the graph designer or when trying to save a tile (on save the error is logged, but it doesn't prevent the save):
"arches/app/models/graph.py", line 224, in __init__
nodes = [models.Node(**node_slug) for node_slug in node_slugs]
^^^^^^^^^^^^^^^^^^^^^^^^
File "arches/app/models/models.py", line 890, in __init__
super(Node, self).__init__(*args, **kwargs)
TypeError: Node() got unexpected keyword arguments: 'grouping_node_id'
And this error when trying to publish an existing model:
g_node_id'
Traceback (most recent call last):
File "/arches/app/views/graph.py", line 688, in post
source_graph.update_from_editable_future_graph()
File "/arches/app/models/graph.py", line 2650, in update_from_editable_future_graph
source_node.nodegroup.grouping_node_id = source_node.nodegroup_id
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'grouping_node_id'
I double checked my migrations, and they seem to have run successfully.
For the first error, that looks like a graph publication dating from an earlier version of this PR when For the second error, nice catch -- I'm going to remove the code that apparently I thought I didn't need two months ago 😄 . Graph publication works for me now. |
for node_dict in published_graph.serialized_graph["nodes"]: | ||
node_dict["grouping_node_id"] = node_dict["nodegroup_id"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the error that I am seeing is caused here. The "grouping_node_id" is getting assigned back to the node. Shouldn't it be assigned to the nodegroup?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, should have retested this. Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that did the trick!
One other thing. I noticed that if I create a new graph and then create a new node, my new node does not have the groupingnodeid assigned. That may be fine because it's a nodegroup of 1, so there really isn't a group to be concerned about. However, if that first node is semantic, and I add another node, then the first semantic node still doesn't have a groupingnodeid. This seems like it could be an issue because it really does have a child node in its group.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ouch, taking a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
Thanks for the reviews! |
Types of changes
Description of Change
Before
From a node, to find the grouping node of that node's nodegroup, you would need to prefetch the sibling nodes and compare the results to the id of the nodegroup, or else just issue another Node.objects.get() to individually fetch the wanted node.
After
There is now a self-referencing foreign key to the other node that serves as the nodegroup root.Per discussion, there is now a OneToOneField on the NodeGroup model pointing to the root node for the nodegroup.
Example query:
Issues Solved
Closes #11613
Checklist
Ticket Background