Ich baue eine Web-App in Django. Ich habe ein Modell, das eine Datei hochlädt, aber ich kann sie nicht löschen. Hier ist mein Code:
class Song(models.Model):
name = models.CharField(blank=True, max_length=100)
author = models.ForeignKey(User, to_field='id', related_name="id_user2")
song = models.FileField(upload_to='/songs/')
image = models.ImageField(upload_to='/pictures/', blank=True)
date_upload = models.DateField(auto_now_add=True)
def delete(self, *args, **kwargs):
# You have to prepare what you need before delete the model
storage, path = self.song.storage, self.song.path
# Delete the model before the file
super(Song, self).delete(*args, **kwargs)
# Delete the file after the model
storage.delete(path)
Dann mache ich in "python manage.py shell" Folgendes:
song = Song.objects.get(pk=1)
song.delete()
Es wird aus der Datenbank gelöscht, jedoch nicht die Datei auf dem Server. Was kann ich noch versuchen?
Vielen Dank!
django
django-models
Marcos Aguayo
quelle
quelle
Antworten:
Vor Django 1.3 wurde die Datei automatisch aus dem Dateisystem gelöscht, wenn Sie die entsprechende Modellinstanz gelöscht haben. Sie verwenden wahrscheinlich eine neuere Django-Version, daher müssen Sie das Löschen der Datei aus dem Dateisystem selbst implementieren.
Sie können dies auf verschiedene Arten tun, von denen eine ein
pre_delete
oder einpost_delete
Signal verwendet.Beispiel
Meine bevorzugte Methode ist derzeit eine Mischung aus
post_delete
undpre_save
Signalen, wodurch veraltete Dateien gelöscht werden, wenn entsprechende Modelle gelöscht oder ihre Dateien geändert werden.Basierend auf einem hypothetischen
MediaFile
Modell:save()
(z. B. durch Massenaktualisierung von aQuerySet
), liegt die alte Datei weiterhin herum, da keine Signale ausgeführt werden. Dies ist nicht der Fall, wenn Sie herkömmliche Methoden zur Dateiverwaltung verwenden.file
als Feldname verwendet. Dies ist kein guter Stil, da er mit der integriertenfile
Objektkennung kollidiert .Siehe auch
FieldFile.delete()
in Django 1.11 Modellfeldreferenz (beachten Sie, dass es dieFieldFile
Klasse beschreibt , aber Sie würden.delete()
direkt das Feld aufrufen :FileField
Instanz-Proxys für die entsprechendeFieldFile
Instanz, und Sie greifen auf ihre Methoden zu, als wären sie Felder)Warum Django Dateien nicht automatisch löscht: Eintrag in Versionshinweisen für Django 1.3
Beispiel für die Verwendung nur eines
pre_delete
Signalsquelle
instance.song.delete(save=False)
, da es die richtige Django-Speicher-Engine verwendet.os.path.isfile(old_file.path)
fehlschlägt, weilold_file.path
ein Fehler ausgelöst wird (dem Feld ist keine Datei zugeordnet). Ich habe es behoben, indem ichif old_file:
kurz vor dem Anruf zu hinzugefügt habeos.path.isfile()
.Versuchen Sie es mit django-cleanup. Beim Entfernen des Modells wird automatisch die Löschmethode in FileField aufgerufen.
settings.py
quelle
Sie können die Datei aus dem Dateisystem löschen
.delete
, indem Sie die unten gezeigte Aufrufmethode des Dateifelds mit Django> = 1.10 aufrufen :quelle
Sie können die Löschfunktion des Modells auch einfach überschreiben, um zu prüfen, ob eine Datei vorhanden ist, und diese löschen, bevor Sie die Superfunktion aufrufen.
quelle
queryset.delete()
die Dateien mit dieser Lösung nicht bereinigt werden. Sie müssten das Abfrageset durchlaufen und.delete()
jedes Objekt aufrufen .Django 2.x Lösung:
In Django 2 ist das Löschen von Dateien sehr einfach . Ich habe versucht, die folgende Lösung mit Django 2 und SFTP Storage sowie FTP STORAGE zu verwenden, und ich bin mir ziemlich sicher, dass sie mit allen anderen Speichermanagern funktioniert, die die
delete
Methode implementiert haben . (delete
Methode ist eine derstorage
abstrakten Methoden.)Überschreiben Sie die
delete
Methode des Modells so, dass die Instanz ihre FileFields löscht, bevor sie sich selbst löscht:Es funktioniert ziemlich einfach für mich. Wenn Sie vor dem Löschen überprüfen möchten, ob eine Datei vorhanden ist, können Sie diese verwenden
storage.exists
. zBself.song.storage.exists(self.song.name)
gibt eineboolean
Darstellung zurück, wenn das Lied existiert. So wird es aussehen:EDIT (zusätzlich):
Wie @HeyMan erwähnt, werden mit dieser Lösung beim Aufrufen
Song.objects.all().delete()
keine Dateien gelöscht! Dies geschieht, weilSong.objects.all().delete()
die Löschabfrage von Default Manager ausgeführt wird . Wenn Sie also Dateien eines Modells mithilfe vonobjects
Methoden löschen möchten , müssen Sie einen benutzerdefinierten Manager schreiben und verwenden (nur um die Löschabfrage zu überschreiben):und um das
CustomManager
dem Modell zuzuweisen, müssen Sieobjects
in Ihrem Modell initialisieren:Jetzt können Sie
.delete()
am Ende alleobjects
Unterabfragen verwenden. Ich habe das einfachste geschriebenCustomManager
, aber Sie können es besser machen, indem Sie etwas über gelöschte Objekte oder was auch immer Sie wollen zurückgeben.quelle
Hier ist eine App, die alte Dateien entfernt, wenn ein Modell gelöscht oder eine neue Datei hochgeladen wird: django-smartfields
quelle
@ Anton Strogonoff
Ich vermisse etwas im Code, wenn eine Datei geändert wird. Wenn Sie eine neue Datei erstellen, wird ein Fehler generiert, da es sich um eine neue Datei handelt, die keinen Pfad gefunden hat. Ich habe den Funktionscode geändert und einen try / without-Satz hinzugefügt, der gut funktioniert.
quelle
try:
Block abzufangen (AttributeError
vielleicht?).Dieser Code wird jedes Mal ausgeführt, wenn ich ein neues Bild (Logo-Feld) hochlade und prüfe, ob bereits ein Logo vorhanden ist. Schließen Sie es und entfernen Sie es von der Festplatte. Das gleiche Verfahren könnte natürlich in der Empfängerfunktion durchgeführt werden. Hoffe das hilft.
quelle