J'utilise 1.2.5 avec un ImageField standard et j'utilise le système de stockage intégré. Les fichiers sont bien téléchargés, mais lorsque je supprime une entrée de l’administrateur, le fichier sur le serveur n’est pas supprimé.
Vous pouvez recevoir le signal pre_delete
ou post_delete
(voir le commentaire de @ toto_tico ci-dessous) et appeler la méthode delete sur l'objet FileField, ainsi (dans models.py):
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)
Essayez Django-cleanup
pip install Django-cleanup
settings.py
INSTALLED_APPS = (
...
'Django_cleanup', # should go after your apps
)
Solution Django 1.5: J'utilise post_delete pour diverses raisons internes à mon application.
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)
Je l'ai collé au bas du fichier models.py.
le champ original_image
est la ImageField
dans mon modèle Photo
.
Ce code fonctionne bien sur Django 1.4 également avec le panneau d’administration.
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)
Il est important d’obtenir le stockage et le chemin d’accès avant de supprimer le modèle, sinon ce dernier restera vide même s’il est supprimé.
Vous avez besoin pour supprimer le fichier réel à la fois delete
et update
.
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)
Vous pouvez envisager d'utiliser un signal pre_delete ou post_delete:
https://docs.djangoproject.com/en/dev/topics/signals/
Bien entendu, les mêmes raisons pour lesquelles la suppression automatique de FileField a été supprimée s'appliquent également ici. Si vous supprimez un fichier référencé ailleurs, vous aurez des problèmes.
Dans mon cas, cela semblait approprié car j'avais un modèle de fichier dédié pour gérer tous mes fichiers.
Remarque: pour une raison quelconque, post_delete ne semble pas fonctionner correctement. Le fichier a été supprimé, mais l'enregistrement de la base de données est resté, ce qui est complètement le contraire de ce à quoi je m'attendais, même dans des conditions d'erreur. pre_delete fonctionne bien cependant.
Peut-être qu'il est un peu tard. Mais le moyen le plus simple pour moi est d’utiliser un signal post_save. N'oubliez pas que les signaux sont exécutés même pendant un processus de suppression QuerySet, mais que la méthode [modèle] .delete () n'est pas exécutée pendant le processus de suppression QuerySet. Ce n'est donc pas la meilleure option pour la remplacer.
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)
"""--------------------------------------------------------------------------"""
noyau/signaux.py
import os
def delete_image_slide(sender, **kwargs):
slide = kwargs.get('instance')
try:
os.remove(slide.image.path)
except:
pass
L'utilisation de post_delete est à coup sûr la bonne solution. Parfois, les choses peuvent mal tourner et les fichiers ne sont pas supprimés. Il existe bien sûr le cas où vous avez un tas d'anciens fichiers qui n'ont pas été supprimés avant l'utilisation de post_delete. J'ai créé une fonction qui supprime les fichiers d'objets en fonction de l'existence du fichier référencé si l'objet n'existe pas, puis supprime l'objet. objet .. Quelque chose que j'ai ajouté à la plupart de mes modèles. Vous devez lui transmettre les objets que vous souhaitez vérifier, le chemin d'accès aux fichiers d'objets, le champ de fichier et un indicateur pour supprimer les objets inactifs:
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."
Voici comment vous pouvez utiliser ceci:
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
Cette fonctionnalité sera supprimée dans Django 1.3, je ne la ferais donc pas.
Vous pouvez remplacer la méthode delete
du modèle en question pour supprimer le fichier avant de supprimer complètement l'entrée de la base de données.
Modifier:
Voici un exemple rapide.
class MyModel(models.Model):
self.somefile = models.FileField(...)
def delete(self, *args, **kwargs):
somefile.delete()
super(MyModel, self).delete(*args, **kwargs)
assurez-vous d'écrire " self " avant le fichier. donc exemple ci-dessus devrait être
def delete(self, *args, **kwargs):
self.somefile.delete()
super(MyModel, self).delete(*args, **kwargs)
J'ai oublié le "moi" avant mon fichier et cela ne fonctionnait pas car il cherchait dans l'espace de noms global.
Si vous avez déjà un certain nombre de fichiers inutilisés dans votre projet et que vous souhaitez les supprimer, vous pouvez utiliser l'utilitaire Django Django-Unnamed-media