2014-05-20 4 views
2

Dans mon projet actuel, mes images sont stockées sur un s3. J'ai un récepteur de signal pre_save pour supprimer l'image réelle du s3 seau sur la classe Image.en utilisant PATCH avec un champ d'image Django et s3

class Image(models.Model): 
    name = models.CharField(max_length = 255) 
    caption = models.CharField(max_length = 255) 
    image = models.ImageField(upload_to='uploads/',blank=True,null=True) 
    rent_property = models.ForeignKey(RentProperty, related_name='Images') 
    is_main_image = models.BooleanField(default=False) 

@receiver(models.signals.pre_save, sender=Image) 
def auto_delete_file_on_change(sender, instance, **kwargs): 
    """Deletes file from filesystem 
    when corresponding `MediaFile` object is changed. 
    """ 
    if not instance.pk: 
     return False 

    try: 
     old_file = Image.objects.get(pk=instance.pk).image 
    except Image.DoesNotExist: 
     return False 

    new_file = instance.image 
    if not old_file == new_file: 
     old_file.delete(save=False) 

Mon problème est, j'utilise django-rest-framework, et je veux que le PATCH fonctionne. mais si j'essaye de patcher une description d'image par exemple, cela effacera l'image elle-même. Ma question est, comment puis-je écrire un IF qui permettrait de différencier la météo ou non, il y a une nouvelle image dans le patch qui a besoin de changer, et sinon, ne rien faire?

+2

habituellement j'enregistre un hachage SHA-1 dans un champ de modèle pour les fichiers de données et vérifier si elle change. Cela fonctionnerait-il dans votre cas? – Fiver

+0

Vous êtes tout à fait le génie. Cela a fonctionné parfaitement. Puisqu'il obtient un nouveau nom unique aléatoire chaque fois qu'il se met à jour, je vérifie juste si c'est changé, sinon, je garde l'ancienne image. Pouvez-vous s'il vous plaît écrire votre commentaire sous la forme d'une réponse afin que je puisse l'accepter et cela pourrait aider d'autres personnes dans le futur? –

+0

Super, content que ça a marché pour vous. J'ai ajouté une réponse avec un peu plus de détails. – Fiver

Répondre

2

Pour les modèles avec un champ ImageField ou FileField, j'inclus un champ supplémentaire pour stocker la chaîne de hachage SHA-1. Je l'ai trouvé ce utile d'avoir pour de nombreuses raisons:

  • réduire les transferts inutiles pour le même dossier pour les mises à jour (votre cas)
  • Empêcher les utilisateurs de télécharger des fichiers en double comme de nouvelles instances
  • offrant aux utilisateurs une SHA-1 hachage lors du téléchargement de fichiers afin qu'ils puissent vérifier le téléchargement
  • Faire des vérifications d'intégrité des données sur le système de fichiers de fin arrière pour vérifier les fichiers ont pas changé

Je sauve aussi le orig nom de fichier inal afin de le reproduire pour les vues/téléchargements en face de l'utilisateur. De cette façon, les noms de back-end ne comptent pas pour les utilisateurs.

est ici une implémentation de base en fonction de votre modèle:

import hashlib 
from django.core.exceptions import ValidationError 
from django.core.files import File 
from django.db import models 

class Image(models.Model): 
    name = models.CharField(max_length = 255) 
    caption = models.CharField(max_length = 255) 
    image = models.ImageField(upload_to='uploads/',blank=True,null=True) 
    original_filename = models.CharField(
     unique=False, 
     null=False, 
     blank=False, 
     editable=False, 
     max_length=256) 
    sha1 = models.CharField(
     unique=True, 
     null=False, 
     blank=False, 
     editable=False, 
     max_length=40) 
    rent_property = models.ForeignKey(RentProperty, related_name='Images') 
    is_main_image = models.BooleanField(default=False) 

    def clean(self): 
     """ 
     Overriding clean to do the following: 
      - Save original file name, since it may already exist on our side. 
      - Save SHA-1 hash and check for duplicate files. 
     """ 

     self.original_filename = self.image.name.split('/')[-1] 
     # get the hash 
     file_hash = hashlib.sha1(self.image.read()) 
     self.sha1 = file_hash.hexdigest() 

     # Check if this file has already been uploaded, 
     # if so delete the temp file and raise ValidationError 
     duplicate_hashes = Image.objects.all().exclude(
       id=self.id).values_list('sha1', flat=True) 
     if self.sha1 in duplicate_hashes: 
      if hasattr(self.image.file, 'temporary_file_path'): 
       temp_file_path = self.image.file.temporary_file_path() 
       os.unlink(temp_file_path) 

      raise ValidationError(
       "This image already exists." 
      ) 
Questions connexes