diff --git a/epdb/apps.py b/epdb/apps.py index 5a1b5b9e..8d43941e 100644 --- a/epdb/apps.py +++ b/epdb/apps.py @@ -4,3 +4,6 @@ from django.apps import AppConfig class EPDBConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'epdb' + + def ready(self): + import epdb.signals # noqa: F401 diff --git a/epdb/models.py b/epdb/models.py index dcd7cad2..5c1770b2 100644 --- a/epdb/models.py +++ b/epdb/models.py @@ -1044,7 +1044,7 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin): return IndigoUtils.mol_to_svg(self.default_node_label.smiles) -class Edge(PolymorphicModel, EnviPathModel, AliasMixin, ScenarioMixin): +class Edge(EnviPathModel, AliasMixin, ScenarioMixin): pathway = models.ForeignKey('epdb.Pathway', verbose_name='belongs to', on_delete=models.CASCADE, db_index=True) edge_label = models.ForeignKey('epdb.Reaction', verbose_name='Edge label', null=True, on_delete=models.SET_NULL) start_nodes = models.ManyToManyField('epdb.Node', verbose_name='Start Nodes', related_name='edge_educts') diff --git a/epdb/signals.py b/epdb/signals.py new file mode 100644 index 00000000..0a87801f --- /dev/null +++ b/epdb/signals.py @@ -0,0 +1,20 @@ +from django.db import transaction +from django.db.models.signals import pre_delete +from django.dispatch import receiver + +from epdb.models import Node, Edge + + +@receiver(pre_delete, sender=Node) +@transaction.atomic +def delete_orphan_edges(sender, instance, **kwargs): + # check if the node that is about to be deleted is the only start node + for edge in Edge.objects.filter(start_nodes=instance): + if edge.start_nodes.count() == 1: + edge.delete() + + # same for end_nodes + for edge in Edge.objects.filter(end_nodes=instance): + # check if the node that is about to be deleted is the only start node + if edge.end_nodes.count() == 1: + edge.delete() diff --git a/epdb/views.py b/epdb/views.py index 1477b762..a178cfc3 100644 --- a/epdb/views.py +++ b/epdb/views.py @@ -1417,15 +1417,20 @@ def package_pathway_node(request, package_uuid, pathway_uuid, node_uuid): return render(request, 'objects/node.html', context) elif request.method == 'POST': - if s.DEBUG: - for k, v in request.POST.items(): - print(k, v) + + log_post_params(request) if hidden := request.POST.get('hidden', None): if hidden == 'delete-node': - current_node.delete() - return redirect(current_pathway.url) + # pre_delete signal will take care of edge deletion + current_node.delete() + + return redirect(current_pathway.url) + else: + return HttpResponseBadRequest() + else: + return HttpResponseBadRequest() else: return HttpResponseNotAllowed(['GET', 'POST']) @@ -1474,6 +1479,8 @@ def package_pathway_edges(request, package_uuid, pathway_uuid): elif request.method == 'POST': + log_post_params(request) + edge_name = request.POST.get('edge-name') edge_description = request.POST.get('edge-description') edge_substrates = request.POST.getlist('edge-substrates') @@ -1517,9 +1524,8 @@ def package_pathway_edge(request, package_uuid, pathway_uuid, edge_uuid): return render(request, 'objects/edge.html', context) elif request.method == 'POST': - if s.DEBUG: - for k, v in request.POST.items(): - print(k, v) + + log_post_params(request) if hidden := request.POST.get('hidden', None): if hidden == 'delete-edge':