PIL (Pillow) est requis pour gérer ImageField, donc si vous n'êtes pas dans l'environnement d'exécution Python, installez-le ci-dessous:
pip install pillow
pip3 install pillow # Python 3.x
J'ai également besoin de définir MEDIA_ROOT
dans settings.py
, alors ajoutez-le:
settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
Ajoutez également ce qui suit à ʻurls.py`:
urls.py
urlpatterns = [
url(r'^media/(?P<path>.*)$','django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
]
Différents champs peuvent être définis dans le modèle de Django, mais il existe ** ImageField ** comme champ pour gérer facilement les fichiers image. Voici l'exemple le plus simple:
class Image(models.Model):
image = models.ImageField(upload_to='images/')
Désormais, lors de l'enregistrement d'un fichier image, il sera enregistré avec MEDIA_ROOT + 'images / (nom du fichier image d'origine)
.
Si le "nom du fichier image d'origine" est couvert, ** Django ajoutera un suffixe étrange et ne l'écrasera pas. ** **
Tout d'abord, je voulais enregistrer l'image en utilisant la clé primaire lors de son enregistrement. Par exemple, le nom du fichier d'origine est car.png, mais si la clé primaire pour la sauvegarde est ʻid = 123 (pk = 123) `, elle sera renommée en 123.png.
ImageField peut modifier librement non seulement le répertoire de destination de sauvegarde de l'image, mais aussi le nom du fichier en donnant une fonction à l'argument ʻupload_to`, mais même si vous faites ce qui suit, par exemple, l'id n'a pas encore été pris lorsque la fonction est appelée. Donc ça ne marche pas:
def get_image_path(self, filename):
prefix = 'images/'
name = self.id #Dans ce cas, l'ID n'a pas encore été décidé lors de la création d'un nouveau, il sera donc Aucun.!!Pas bien
extension = os.path.splitext(filename)[-1]
return prefix + name + extension
Ensuite, lorsque self.id
est None
, c'est une façon de prendre max (id) + 1
de DB et de l'utiliser, mais cela dépend de DB, mais l'id suivant n'est pas nécessairement max (id). Il manque de rigueur car il ne devient pas id) + 1
.
Selon StackOverFlow, il est dit: "Enregistrez-le avec un nom approprié pour le moment, et si l'ID est décidé après l'enregistrement, vous devez le renommer avec le nom de fichier correct." J'ai également essayé cela, mais le fichier réel est certainement C'est bien, mais le chemin dans la base de données est encore ancien, donc c'est étrange quand je le vois avec l'administrateur Django.
Plus tard, par exemple, si vous l'enregistrez sous 123.png et mettez à jour l'image, vous ne pouvez pas ** écraser 123.png, et ** 123 créera un fichier incompréhensible appelé .png. C'est parce que Django n'autorise pas l'écrasement. Pour faire face à cela, vous devez supprimer l'ancien fichier à l'avance, puis l'enregistrer ...
J'ai renoncé à enregistrer le nom du fichier image avec la clé primaire car cela devenait ennuyeux quand j'y pensais.
Si vous souhaitez créer un nom de fichier normalement unique, vous pouvez utiliser UUID, j'ai donc essayé ce qui suit:
def get_image_path(self, filename):
"""Obtenez un chemin d'image personnalisé.
:param self:exemple(models.Model)
:param filename:Nom du fichier d'origine
:return:Chemin de l'image contenant le nom de fichier personnalisé
"""
prefix = 'images/'
name = str(uuid.uuid4()).replace('-', '')
extension = os.path.splitext(filename)[-1]
return prefix + name + extension
Maintenant, il est enregistré avec un nom tel que images / 7f9a9970cc8645a99a2191c114856426.jpg. Cependant, même si ImageField est mis à jour ou supprimé sur le site de gestion tel quel, il y a un problème que l'enregistrement DB disparaît mais le fichier d'origine reste. Je veux faire quelque chose à ce sujet.
Comme le titre l'indique, je veux supprimer les anciens fichiers et les rendre plus propres lorsque save ()
ou delete ()
. Il est conseillé d'enregistrer l'ancien chemin du fichier avant de mettre à jour / de supprimer, puis de supprimer l'ancien fichier une fois le traitement effectué. C'est là qu'intervient le décorateur.
def delete_previous_file(function):
"""Implémentation de Decorator pour supprimer les anciens fichiers qui ne sont plus nécessaires.
:param function:Fonction principale
:return: wrapper
"""
def wrapper(*args, **kwargs):
"""Fonction wrapper.
:param args:Argument arbitraire
:param kwargs:Argument de mot clé arbitraire
:return:Résultat d'exécution de la fonction principale
"""
self = args[0]
#Obtenez le nom du fichier avant d'enregistrer
result = Image.objects.filter(pk=self.pk)
previous = result[0] if len(result) else None
super(Image, self).save()
#Exécution de la fonction
result = function(*args, **kwargs)
#Supprimer tous les fichiers avant de les enregistrer
if previous:
os.remove(MEDIA_ROOT + '/' + previous.image.name)
return result
return wrapper
Préparez une fonction pour un tel décorateur,
class Image(models.Model):
@delete_previous_file
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
super(Image, self).save()
@delete_previous_file
def delete(self, using=None, keep_parents=False):
super(Image, self).delete()
image = models.ImageField('image', upload_to=get_image_path)
Ce faisant, les anciens fichiers seront supprimés lors de la mise à jour / suppression.