it-swarm.com.de

Wie kann ich Django Admin dazu bringen, Dateien zu löschen, wenn ich ein Objekt aus der Datenbank/Modell entferne?

Ich verwende 1.2.5 mit einem Standard-ImageField und verwende das integrierte Speicher-Backend. Das Hochladen von Dateien ist in Ordnung, aber wenn ich einen Eintrag aus Admin entferne, wird die eigentliche Datei auf dem Server nicht gelöscht.

79
narkeeso

Sie können das Signal pre_delete oder post_delete empfangen (siehe den Kommentar von @toto_tico unten) und die delete-Methode für das FileField-Objekt aufrufen.

class MyModel(models.Model):
    file = models.FileField()
    ...

# Receive the pre_delete signal and delete the file associated with the model instance.
from Django.db.models.signals import pre_delete
from Django.dispatch.dispatcher import receiver

@receiver(pre_delete, sender=MyModel)
def mymodel_delete(sender, instance, **kwargs):
    # Pass false so FileField doesn't save the model.
    instance.file.delete(False)
93
darrinm

Versuchen Sie Django-Aufräumen

pip install Django-cleanup

einstellungen.py

INSTALLED_APPS = (
    ...
    'Django_cleanup', # should go after your apps
)
40
un1t

Django 1.5 Lösung: Ich verwende post_delete aus verschiedenen Gründen, die in meiner App enthalten sind.

from Django.db.models.signals import post_delete
from Django.dispatch import receiver

@receiver(post_delete, sender=Photo)
def photo_post_delete_handler(sender, **kwargs):
    photo = kwargs['instance']
    storage, path = photo.original_image.storage, photo.original_image.path
    storage.delete(path)

Ich habe dies am unteren Rand der Datei models.py geklebt.

das original_image-Feld ist die ImageField in meinem Photo-Modell.

34
Kushal

Dieser Code läuft auf Django 1.4 auch im Admin-Bereich gut.

class ImageModel(models.Model):
    image = ImageField(...)

    def delete(self, *args, **kwargs):
        # You have to prepare what you need before delete the model
        storage, path = self.image.storage, self.image.path
        # Delete the model before the file
        super(ImageModel, self).delete(*args, **kwargs)
        # Delete the file after the model
        storage.delete(path)

Es ist wichtig, dass der Speicher und der Pfad vor dem Löschen des Modells abgerufen werden. Andernfalls bleibt das Modell auch beim Löschen ungültig.

17

Sie brauchen, um die tatsächliche Datei von delete und update zu entfernen.

from Django.db import models

class MyImageModel(models.Model):
    image = models.ImageField(upload_to='images')

    def remove_on_image_update(self):
        try:
            # is the object in the database yet?
            obj = MyImageModel.objects.get(id=self.id)
        except MyImageModel.DoesNotExist:
            # object is not in db, nothing to worry about
            return
        # is the save due to an update of the actual image file?
        if obj.image and self.image and obj.image != self.image:
            # delete the old image file from the storage in favor of the new file
            obj.image.delete()

    def delete(self, *args, **kwargs):
        # object is being removed from db, remove the file from storage first
        self.image.delete()
        return super(MyImageModel, self).delete(*args, **kwargs)

    def save(self, *args, **kwargs):
        # object is possibly being updated, if so, clean up.
        self.remove_on_image_update()
        return super(MyImageModel, self).save(*args, **kwargs)
8
un33k

Sie können ein pre_delete- oder post_delete-Signal verwenden:

https://docs.djangoproject.com/de/dev/topics/signals/

Natürlich gelten auch hier die gleichen Gründe, warum FileField automatisch gelöscht wurde. Wenn Sie eine Datei löschen, auf die an anderer Stelle verwiesen wird, treten Probleme auf.

In meinem Fall schien dies angemessen zu sein, da ich über ein dediziertes Dateimodell verfügte, um alle meine Dateien zu verwalten.

Hinweis: Aus irgendeinem Grund scheint post_delete nicht richtig zu funktionieren. Die Datei wurde gelöscht, aber der Datenbanksatz blieb erhalten, was völlig anders ist als ich erwartet hätte, selbst unter Fehlerbedingungen. pre_delete funktioniert aber gut.

6
SystemParadox

Vielleicht ist es etwas spät. Am einfachsten ist es für mich, ein post_save-Signal zu verwenden. Beachten Sie, dass Signale auch während eines QuerySet-Löschvorgangs ausgeführt werden. Die Methode [model] .delete () wird jedoch während des QuerySet-Löschvorgangs nicht ausgeführt. Daher ist es nicht die beste Option, sie zu überschreiben.

core/models.py:

from Django.db import models
from Django.db.models.signals import post_delete
from core.signals import delete_image_slide
SLIDE1_IMGS = 'slide1_imgs/'

class Slide1(models.Model):
    title = models.CharField(max_length = 200)
    description = models.CharField(max_length = 200)
    image = models.ImageField(upload_to = SLIDE1_IMGS, null = True, blank = True)
    video_embed = models.TextField(null = True, blank = True)
    enabled = models.BooleanField(default = True)

"""---------------------------- SLIDE 1 -------------------------------------"""
post_delete.connect(delete_image_slide, Slide1)
"""--------------------------------------------------------------------------"""

kern/Signale.py

import os

def delete_image_slide(sender, **kwargs):
    slide = kwargs.get('instance')
    try:
        os.remove(slide.image.path)
    except:
        pass
3
Mauricio

Die Verwendung von post_delete ist sicher der richtige Weg. Manchmal kann es jedoch schief gehen und Dateien werden nicht gelöscht. Natürlich gibt es eine Reihe alter Dateien, die nicht gelöscht wurden, bevor post_delete verwendet wurde. Ich habe eine Funktion erstellt, die Dateien für Objekte löscht, wenn die Datei keine Objektreferenzen enthält. Dann Objekt löschen. Wenn die Datei kein Objekt enthält, dann auch löschen. Außerdem kann sie basierend auf einem aktiven Flag für ein Objekt gelöscht werden Objekt .. Etwas, das ich den meisten meiner Modelle hinzugefügt habe. Sie müssen die zu überprüfenden Objekte, den Pfad zu den Objektdateien, das Dateifeld und ein Flag zum Löschen inaktiver Objekte übergeben:

def cleanup_model_objects(m_objects, model_path, file_field='image', clear_inactive=False):
    # PART 1 ------------------------- INVALID OBJECTS
    #Creates photo_file list based on photo path, takes all files there
    model_path_list = os.listdir(model_path)

    #Gets photo image path for each photo object
    model_files = list()
    invalid_files = list()
    valid_files = list()
    for obj in m_objects:

        exec("f = ntpath.basename(obj." + file_field + ".path)")  # select the appropriate file/image field

        model_files.append(f)  # Checks for valid and invalid objects (using file path)
        if f not in model_path_list:
            invalid_files.append(f)
            obj.delete()
        else:
            valid_files.append(f)

    print "Total objects", len(model_files)
    print "Valid objects:", len(valid_files)
    print "Objects without file deleted:", len(invalid_files)

    # PART 2 ------------------------- INVALID FILES
    print "Files in model file path:", len(model_path_list)

    #Checks for valid and invalid files
    invalid_files = list()
    valid_files = list()
    for f in model_path_list:
        if f not in model_files:
            invalid_files.append(f)
        else:
            valid_files.append(f)
    print "Valid files:", len(valid_files)
    print "Files without model object to delete:", len(invalid_files)

    for f in invalid_files:
        os.unlink(os.path.join(model_path, f))

    # PART 3 ------------------------- INACTIVE PHOTOS
    if clear_inactive:
        #inactive_photos = Photo.objects.filter(active=False)
        inactive_objects = m_objects.filter(active=False)
        print "Inactive Objects to Delete:", inactive_objects.count()
        for obj in inactive_objects:
            obj.delete()
    print "Done cleaning model."

So können Sie dies nutzen:

photos = Photo.objects.all()
photos_path, tail = ntpath.split(photos[0].image.path)  # Gets dir of photos path, this may be different for you
print "Photos -------------->"
cleanup_model_objects(photos, photos_path, file_field='image', clear_inactive=False)  # image file is default
1
radtek

Diese Funktionalität wird in Django 1.3 entfernt, sodass ich mich nicht darauf verlassen würde. 

Sie können die delete-Methode des betreffenden Modells überschreiben, um die Datei zu löschen, bevor Sie den Eintrag vollständig aus der Datenbank entfernen.

Bearbeiten:

Hier ist ein kurzes Beispiel.

class MyModel(models.Model):

    self.somefile = models.FileField(...)

    def delete(self, *args, **kwargs):
        somefile.delete()

        super(MyModel, self).delete(*args, **kwargs)
1
Derek Reynolds

stellen Sie sicher, dass Sie " self " vor der Datei schreiben. so soll das Beispiel oben sein

def delete(self, *args, **kwargs):
        self.somefile.delete()

        super(MyModel, self).delete(*args, **kwargs)

Ich habe das "Ich" vor meiner Datei vergessen und das hat nicht funktioniert, da es im globalen Namensraum gesucht wurde.

0
Bjorn

Wenn Sie bereits eine Anzahl nicht verwendeter Dateien in Ihrem Projekt haben und löschen möchten, können Sie das Dienstprogramm Django Django-unused-media

0
Andrey Kolpakov