Переопределить метод удаления модели django для массового удаления

Я переопределяю метод удаления модели Django, чтобы удалить сиротские файлы на диске для полей изображений, что-то вроде этого:

class Image(models.Model):
    img = models.ImageField(upload_to=get_image_path)
    ...
    def delete(self, *args, **kwargs):
        self.img.delete()
        super(Image, self).delete(*args, **kwargs)

это отлично работает, когда я удаляю отдельные объекты из администратора, но когда я выбираю несколько объектов и удаляю их, это, похоже, не вызывается. Я некоторое время гуглил, но не попал в правильные ключевые слова, чтобы получить ответ на этот вопрос, и официальная документация, похоже, говорит об этой теме.

2 ответов


это:

метод delete () выполняет массовое удаление и не вызывает никаких методов delete () на ваших моделях. Однако он выдает сигналы pre_delete и post_delete для всех удаленных объектов (включая каскадные удаления).

для этого вы можете переопределить метод delete на QuerySet, а затем применить эти QuerySet менеджер:

class ImageQuerySet(models.QuerySet):

    def delete(self, *args, **kwargs):
        for obj in self:
            obj.img.delete()
        super(ImageQuerySet, self).delete(*args, **kwargs)

class Image(models.Model):
    objects = ImageQuerySet.as_manager()
    img = models.ImageField(upload_to=get_image_path)
    ...
    def delete(self, *args, **kwargs):
        self.img.delete()
        super(Image, self).delete(*args, **kwargs)

Delete метод queryset работает непосредственно на базе данных. Он не зовет Model.delete() методы. От docs:

имейте в виду, что это, когда это возможно, будет выполняться исключительно в SQL, и поэтому методы delete() отдельных экземпляров объектов не обязательно будут вызываться во время процесса. Если вы предоставили пользовательский метод delete () для класса модели и хотите убедиться, что он вызван, вам нужно будет "вручную" удалить экземпляры этого модель (например, путем итерации по QuerySet и вызова delete () для каждого объекта по отдельности), а не с помощью метода bulk delete () QuerySet.

если вы хотите переопределить поведение интерфейса администрирования Django по умолчанию, вы можете написать пользовательский delete действие:

https://docs.djangoproject.com/en/1.7/ref/contrib/admin/actions/

другой метод-переопределить post_delete (или pre_delete) сигнала вместо delete метод:

https://docs.djangoproject.com/en/1.7/ref/signals/#django.db.models.signals.post_delete

как pre_delete, но отправлено в конце метода delete () модели и метод delete() queryset.