From 40ed2d2e22618dd006fdcca4930352d5be9a4e3c Mon Sep 17 00:00:00 2001 From: Nathan Panchout Date: Mon, 17 Mar 2025 14:46:59 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(back)=20keep=20info=20if=20documen?= =?UTF-8?q?t=20has=20deleted=20children?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the soft delete feature, relying on the is_leaf method from the treebeard is not accurate anymore. To determine if a node is a leaf, it checks if the number of numchild is equal to 0. But a node can have soft deleted children, then numchild is equal to 0, but it is not a leaf because if we want to add a child we have to look for the last child to compute a correct path. Otherwise we will have an error saying that the path already exists. --- .../0021_remove_document_is_public_and_more.py | 17 +++++++++++++++++ src/backend/core/models.py | 10 +++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/backend/core/migrations/0021_remove_document_is_public_and_more.py diff --git a/src/backend/core/migrations/0021_remove_document_is_public_and_more.py b/src/backend/core/migrations/0021_remove_document_is_public_and_more.py new file mode 100644 index 00000000..97eaa468 --- /dev/null +++ b/src/backend/core/migrations/0021_remove_document_is_public_and_more.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.7 on 2025-03-14 14:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0020_remove_is_public_add_field_attachments_and_duplicated_from"), + ] + + operations = [ + migrations.AddField( + model_name="document", + name="has_deleted_children", + field=models.BooleanField(default=False), + ), + ] diff --git a/src/backend/core/models.py b/src/backend/core/models.py index 5c2172fd..d6e79c51 100644 --- a/src/backend/core/models.py +++ b/src/backend/core/models.py @@ -384,6 +384,7 @@ class Document(MP_Node, BaseModel): ) deleted_at = models.DateTimeField(null=True, blank=True) ancestors_deleted_at = models.DateTimeField(null=True, blank=True) + has_deleted_children = models.BooleanField(default=False) duplicated_from = models.ForeignKey( "self", on_delete=models.SET_NULL, @@ -465,6 +466,12 @@ class Document(MP_Node, BaseModel): content_file = ContentFile(bytes_content) default_storage.save(file_key, content_file) + def is_leaf(self): + """ + :returns: True if the node is has no children + """ + return not self.has_deleted_children and self.numchild == 0 + @property def key_base(self): """Key base of the location where the document is stored in object storage.""" @@ -886,7 +893,8 @@ class Document(MP_Node, BaseModel): if self.depth > 1: self._meta.model.objects.filter(pk=self.get_parent().pk).update( - numchild=models.F("numchild") - 1 + numchild=models.F("numchild") - 1, + has_deleted_children=True, ) # Mark all descendants as soft deleted