1

I have an Annonce page with this model:

class AnnoncePage(Page):
    date = models.DateField("Date de publication", blank=True, null=True)
    description = RichTextField(features=['h2', 'h3', 'bold', 'italic', 'link', 'hr', 'ol', 'ul'], blank=True)
    lieu = models.CharField(blank=True, max_length=200)
    surface = models.PositiveSmallIntegerField(blank=True, null=True)
    nb_pieces = models.PositiveSmallIntegerField(blank=True, null=True)
    prix_affiché_index = models.CharField(blank=True, max_length=200, null=True)
    conditions_vente_et_prix = RichTextField(blank=True, features=['h2', 'h3', 'bold', 'italic', 'link', 'hr', 'ol', 'ul'])

    def main_image(self):
        gallery_item = self.gallery_images.first()
        if gallery_item:
            return gallery_item.image
        else:
            return None

    content_panels = Page.content_panels + [
        FieldPanel('date'),
        InlinePanel('gallery_images', label="Gallery images"),
        FieldPanel('lieu', classname="full"),
        FieldPanel('surface', classname="full"),
        FieldPanel('nb_pieces', classname="full"),
        FieldPanel('description', classname="full"),
        FieldPanel('prix_affiché_index', classname="full"),
        FieldPanel('conditions_vente_et_prix', classname="full")
    ]

    promote_panels = []
    settings_panels = []

    max_count = 20

class AnnoncePageGalleryImage(Orderable):
    page = ParentalKey(AnnoncePage, on_delete=models.SET_NULL, related_name='gallery_images', null=True)
    image = models.ForeignKey(
        'wagtailimages.Image', on_delete=models.SET_NULL, related_name='+', null=True
    )

    panels = [
        ImageChooserPanel('image')
    ]

How can I automaticaly delete the images of the Annonce page after deleting the Annonce page itself ? Do I need to change the model ?

Pierrocana
  • 13
  • 4
  • Use `on_delete=models.CASCADE` on `AnnoncePageGalleryImage.page` https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.CASCADE – allcaps Oct 10 '20 at 22:29
  • @allcaps Even with on_delete=models.CASCADE on AnnoncePageGalleryImage.page, the AnnoncePage images are still here after deleting AnnoncePage instance. – Pierrocana Oct 12 '20 at 09:37
  • The database entries? Or the files on disk? – allcaps Oct 12 '20 at 12:15
  • @allcaps In the database after deleting an AnnoncePage, annonce_annoncepagegalleryimage entries are deleted but wagttailimages_image entries are still here. Like there were no CASCADE – Pierrocana Oct 13 '20 at 08:57

1 Answers1

0

The Wagtail image object can be used in other places. Deleting those automagically might have nasty side effects for other content.

You can add a delete method to AnnoncePage or use a pre_delete signal. You need to iterate over all related gallery images and delete the related Wagtail images. Django leaves the file on disk, so you might want to handle that too.

class AnnoncePage(Page):
    ...
    def delete(self):
         for gallery_image in self.gallery_images.all():
              # Delete the file on disk here ...
              # After, delete the db obj.
              gallery_image.image.all().delete()
         self.gallery_images.all().delete()
         super().delete()

Disclaimer: untested code.

https://docs.djangoproject.com/en/dev/topics/db/models/#overriding-model-methods https://docs.djangoproject.com/en/dev/ref/signals/#pre-delete https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.fields.files.FieldFile.delete

Note that the delete method and pre_delete signal are not called on bulk actions. Your milage may vary.

allcaps
  • 10,945
  • 1
  • 33
  • 54
  • Following your instructions I'm getting an error: Exception Type: AttributeError at /admin/pages/34/delete/ Exception Value: 'DeferringRelatedManager' object has no attribute 'delete' – Pierrocana Oct 13 '20 at 10:55
  • `self.gallery_images.all().delete()` – allcaps Oct 13 '20 at 11:30
  • `gallery_image.image.all().delete()` – allcaps Oct 13 '20 at 11:30
  • Your new code succefully deleted images but it blocked the deletion of the AnnoncePage itself. So I added ` Page.objects.filter(id=self.id).delete()` too the delete method. Now it working as I want, thank you – Pierrocana Oct 13 '20 at 13:32
  • Great! We should call super. That executes the delete method on the Page class. – allcaps Oct 13 '20 at 18:43