Wagtail: delete() method not called in Page instance

Viewed 15

I want to automatically create a Collection when a Page instance is saved and link it to the page using a FK, and it needs to be deleted if the page instance is deleted.

class CustomProject(BasePage):
    description = models.TextField(_("description"), default="", blank=True)
    main_section_image = models.ForeignKey(
        "wagtailimages.Image",
        verbose_name=_("Main section image"),
        on_delete=models.PROTECT,
        related_name="+",
    )
    images_collection = models.ForeignKey(
        Collection,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        editable=False,
    )

    content_panels = BasePage.content_panels + [
        FieldPanel("description", classname="full"),
        FieldPanel("main_section_image"),
        HelpPanel(_(
            "To manage the project's photos, firstly save this page's changes "
            "(either as Draft or Published) and then go to the "
            "<a href=\"/cms/images\">%(url_label)s</a>, "
            "select the collection with the same namne as this project and "
            "there add the images."
        ) % {"url_label": "Images section"}),
    ]

    parent_page_types = ["cms_site.CustomProjectsPage"]
    page_description = _("Custom project page.")
    template = "pages/custom_projects/custom_project.html"

    def save(self, clean=True, user=None, log_action=False, **kwargs):
        self.create_or_update_collection()
        return super().save(clean, user, log_action, **kwargs)

    def delete(self, *args, **kwargs):
        print("calling delete")
        self.delete_collection()
        super().delete(self, *args, **kwargs)

    def create_or_update_collection(self):
        collection_name = f"[Projecte a mida] {self.title}"
        if not self.images_collection:
            root_node = Collection.objects.get(id=get_root_collection_id())
            new_collection = root_node.add_child(name=collection_name)
            self.images_collection = new_collection
        else:
            self.images_collection.name = collection_name
            self.images_collection.save()

    def delete_collection(self):
        if self.images_collection:
            Collection.objects.get(id=self.images_collection.id).delete()

The delete() method is not called at all, neither deleting a Draft or a Published instance. The save() is working perfectly fine in both cases.

Is that the expected behavior for some reason? Should I rely only in something like signals or hooks for this purpose? (I imagine that's the answer, but I still don't get why the save is called and the delete is not)

BassePage is not messing with it, I don't think it's relevant but i paste it here to share the full code:

class BasePage(Page):
    header_image = models.ForeignKey(
        "wagtailimages.Image",
        verbose_name=_("Header image"),
        on_delete=models.PROTECT,
        related_name="+",
        null=True,
        blank=False,
    )

    content_panels = Page.content_panels + [
        FieldPanel("header_image"),
    ]
    show_in_menus_default = False

    class Meta:
        abstract = True

Thanks a lot!

Edit: in case someone wants an example on how to implement it using hooks, is really simple and well documented.

Just create a wagtail_hooks.py file at the root of your app with:

from wagtail import hooks
from wagtail.models import Collection

from apps.cms_site.models import CustomProject


@hooks.register("after_delete_page")
def after_delete_custom_project(request, page):
    if (
        request.method == 'POST'
        and page.specific_class is CustomProject
        and page.images_collection
    ):
        Collection.objects.get(id=page.images_collection.id).delete()
0 Answers
Related