webentwicklung-frage-antwort-db.com.de

Wie überschreibe ich delete () in einem Modell und lasse es trotzdem mit verwandten Löschvorgängen arbeiten?

Ich habe ein Problem, weil ich ein Widget mit some_widget_instance.delete () lösche. Ich habe auch ein Modell namens WidgetFile mit einer override delete () -Methode, damit ich Dateien von meiner Festplatte löschen kann, wenn eine WidgetFile gelöscht wird. Das Problem, das ich habe, ist, dass wenn ich ein Widget lösche und WidgetFiles wie folgt damit verknüpft sind:

class WidgetFile(models.Model):

    widget = models.ForeignKey(Widget)

Nun, wenn ich dieses Widget lösche, werden die Widget-Dateien gelöscht, aber die delete () -Methode wird nicht ausgelöst und erledigt meine zusätzlichen Festplatten-Aufgaben nicht. Jede Hilfe wird sehr geschätzt.

20
orokusaki

Ich habe es herausgefunden. Ich habe dies gerade auf das Widget-Modell gesetzt:

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

Dies löste die erforderliche delete () -Methode für jedes der verwandten Objekte aus, wodurch der Löschcode für meine benutzerdefinierte Datei ausgelöst wurde. Ja, es ist datenbankintensiver, aber wenn Sie versuchen, Dateien auf einer Festplatte zu löschen, ist es nicht so teuer, die Datenbank ein paar zusätzliche Male aufzusuchen.

31
orokusaki

Ich mache dasselbe und habe ein Nugget in den Django-Dokumenten entdeckt, über das Sie nachdenken sollten.

Überschreiben vordefinierter Modellmethoden

Überschreiben von Delete Beachten Sie, dass die delete () -Methode für ein Objekt nicht unbedingt aufgerufen wird, wenn Objekte mithilfe eines QuerySet-Objekts in großen Mengen gelöscht werden. Um sicherzustellen, dass die angepasste Löschlogik ausgeführt wird, können Sie Pre_Delete- und/oder Post_Delete-Signale verwenden.

Dies bedeutet, dass Ihr Snippet nicht immer das tut, was Sie wollen. Die Verwendung von Signalen ist eine bessere Option für den Umgang mit Löschungen.

Ich ging mit folgenden:

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)
60
ElementalVoid

Wenn Sie clear() vor dem Löschen verwenden, werden alle Objekte aus dem zugehörigen Objektsatz entfernt.

siehe Django-folgenden-Beziehungen-rückwärts

beispiel:

group.link_set.clear() 
group.delete() 
2
panchicore

Dies scheint nur sinnvoll zu sein, wenn genau ein Widget mit einem WidgetFile verbunden ist. In diesem Fall sollten Sie ein OneToOneField verwenden.

von Einzelbeispiele:

# Delete the restaurant; the waiter should also be removed
>>> r = Restaurant.objects.get(pk=1)
>>> r.delete()
1
vikingosegundo

Um dieses Problem auf eine mögliche Weise zu umgehen: VorlöschenSignal . (Das bedeutet keineswegs, dass es keine tatsächliche Lösung gibt.)

1
che

Es sollte so aussehen, wie auf der Django Seite beschrieben:

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/de/dev/topics/db/models/#overriding-predefined-model-methods

sie haben vergessen, einige Argumente zu übergeben

1

Ist some_widget_instance und Instanz von Widget oder von WidgetFile? Wenn es sich um eine Instanz von Widget handelt, wird die benutzerdefinierte Funktion delete() in der Klasse WidgetFile nicht abgerufen.

0
thornomad

Wenn Sie in Django 1.9 nur on_delete=models.CASCADE für Feld definieren, werden alle verwandten Objekte beim Löschen entfernt.

0
CLTanuki