Как переопределить delete () для модели и по-прежнему работать с соответствующими удалениями - PullRequest
22 голосов
/ 08 октября 2009

У меня проблема, потому что я удаляю виджет с помощью some_widget_instance.delete (). У меня также есть модель WidgetFile с методом override delete (), так что я могу удалять файлы с моего жесткого диска при удалении WidgetFile. У меня проблема в том, что, если я удаляю виджет, и у него есть связанные с ним файлы Widget, например:

class WidgetFile(models.Model):

    widget = models.ForeignKey(Widget)

Что ж, когда я удаляю этот Widget, его WidgetFiles удаляются, но метод delete () не запускается и не выполняет мои дополнительные операции с жестким диском. Любая помощь очень ценится.

Ответы [ 8 ]

63 голосов
/ 01 октября 2012

Я делаю то же самое и заметил самородок в документах Django, о котором вы должны подумать.

Переопределение предопределенных методов модели

Переопределение Удалить Обратите внимание, что метод delete () для объекта не обязательно вызывается при массовом удалении объектов с использованием QuerySet. Чтобы обеспечить выполнение настроенной логики удаления, вы можете использовать сигналы pre_delete и / или post_delete.

Это означает, что ваш фрагмент не будет всегда делать то, что вы хотите. Использование Сигналы - лучший вариант для удаления.

Я пошел со следующим:

import shutil
from django.db.models.signals import pre_delete 
from django.dispatch import receiver

@receiver(pre_delete)
def delete_repo(sender, instance, **kwargs):
    if sender == Set:
        shutil.rmtree(instance.repo)
32 голосов
/ 08 октября 2009

Я понял это. Я просто поместил это на эту модель виджета:

def delete(self):
    files = WidgetFile.objects.filter(widget=self)
    if files:
        for file in files:
            file.delete()
    super(Widget, self).delete()

Это вызвало необходимый метод delete () для каждого из связанных объектов, что вызвало мой собственный код удаления файлов. Да, это дороже, чем база данных, но когда вы все равно пытаетесь удалить файлы на жестком диске, не так уж и много стоит потратить несколько раз на БД.

2 голосов
/ 08 октября 2009

Использование clear() перед удалением удаляет все объекты из набора связанных объектов.

см. django-follow-Relations-Backward

пример:

group.link_set.clear() 
group.delete() 
1 голос
/ 25 мая 2011

Это должно выглядеть так, как описано на сайте django :

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()
    def save(self, *args, **kwargs):
        do_something()
        super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
        do_something_else()

http://docs.djangoproject.com/en/dev/topics/db/models/#overriding-predefined-model-methods

Вы забыли передать некоторые аргументы

1 голос
/ 08 октября 2009

Просто, чтобы обойти эту проблему: pre-delete signal . (Ни в коем случае не подразумевает, что нет реального решения.)

1 голос
/ 08 октября 2009

Кажется, что это будет просто, если один Widget точно связан с одним WidgetFile. В этом случае вы должны использовать OneToOneField

из Примеры один на один:

# Delete the restaurant; the waiter should also be removed
>>> r = Restaurant.objects.get(pk=1)
>>> r.delete()
0 голосов
/ 09 апреля 2016

В Django 1.9, если вы просто определите on_delete=models.CASCADE для поля, оно удалит все связанные объекты при удалении.

0 голосов
/ 08 октября 2009

Это some_widget_instance и экземпляр Widget или WidgetFile? Потому что, если это экземпляр Widget, он не получит пользовательскую функцию delete(), которая находится в классе WidgetFile.

...