2009-03-12 10 views
3

J'essaie de renommer un fichier après l'avoir téléchargé dans la méthode de sauvegarde du modèle. Je renommer le fichier à une combinaison de la clé primaire des fichiers et un slug du titre du fichier.Django: fichier transféré verrouillé. Impossible de renommer

Je l'ai qui fonctionne quand un fichier est d'abord téléchargé, quand un nouveau fichier est téléchargé, et quand il n'y a pas de changements dans le fichier ou le titre du fichier.

Cependant, lorsque le titre du fichier est modifié, et le système essaie de renommer l'ancien fichier vers le nouveau chemin que je reçois l'erreur suivante:

WindowsError at /admin/main/file/1/ 
(32, 'The process cannot access the file because it is being used by another process') 

Je ne sais pas vraiment comment obtenir autour de ça. J'ai essayé juste de copier le fichier sur le nouveau chemin. Cela fonctionne, mais je ne sais pas que je peux supprimer l'ancienne version.

Modèle raccourcies:

class File(models.Model): 
    nzb = models.FileField(upload_to='files/') 
    name = models.CharField(max_length=256) 
    name_slug = models.CharField(max_length=256, blank=True, null=True, editable=False) 

    def save(self): 
     # Create the name slug. 
     self.name_slug = re.sub('[^a-zA-Z0-9]', '-', self.name).strip('-').lower() 
     self.name_slug = re.sub('[-]+', '-', self.name_slug) 

     # Need the primary key for naming the file. 
     super(File, self).save() 

     # Create the system paths we need. 
     orignal_nzb = u'%(1)s%(2)s' % {'1': settings.MEDIA_ROOT, '2': self.nzb} 
     renamed_nzb = u'%(1)sfiles/%(2)s_%(3)s.nzb' % {'1': settings.MEDIA_ROOT, '2': self.pk, '3': self.name_slug} 

     # Rename the file. 
     if orignal_nzb not in renamed_nzb: 
      if os.path.isfile(renamed_nzb): 
       os.remove(renamed_nzb) 

      # Fails when name is updated. 
      os.rename(orignal_nzb, renamed_nzb) 

     self.nzb = 'files/%(1)s_%(2)s.nzb' % {'1': self.pk, '2': self.name_slug} 

     super(File, self).save() 

Je suppose que la question est-ce que quelqu'un sait comment je peux renommer un fichier téléchargé lorsque le fichier téléchargé est pas téléchargé à nouveau? C'est la seule fois où il semble être verrouillé/utilisé.


Mise à jour:

approche de Tyler travaille, sauf lorsqu'un nouveau fichier est téléchargé la clé primaire n'est pas disponible et sa technique est de lancer une erreur ci-dessous.

if not instance.pk: 
    instance.save() 

Erreur:

maximum recursion depth exceeded while calling a Python object 

Est-il possible de saisir la clé primaire?

+0

Je me demandais en fait pourquoi il n'y a pas de fonction move/rename sur le FileField. – Powerlord

Répondre

5

Je pense que vous devriez regarder de plus près le champ upload_to. Ce serait probablement plus simple que de déconner avec renommer pendant la sauvegarde.

http://docs.djangoproject.com/en/dev/ref/models/fields/#filefield

This may also be a callable, such as a function, which will be called to obtain the upload path, including the filename. This callable must be able to accept two arguments, and return a Unix-style path (with forward slashes) to be passed along to the storage system. The two arguments that will be passed are:

+0

Mais cet appel n'est-il pas seulement utilisé quand un fichier est réellement téléchargé? Si tel est le cas, il ne suffit pas de le spécifier pour renommer un fichier existant uniquement lorsqu'une instance de modèle est enregistrée. –

+0

Je crois que Guðmundur est correct. Si le champ upload_to était utilisé et que le titre du fichier était mis à jour, le fichier ne serait pas renommé avec le nouveau titre. –

+0

Mon point est que renommer après le fait n'est pas bien pris en charge. Renommer plus tôt dans le processus est bien pris en charge. Il serait peut-être utile de repenser la solution pour qu'elle corresponde mieux à ce que Django fait hors de la boîte. –

0

Une fois téléchargé, vous avez tout est un objet image en mémoire, non?

Vous pouvez enregistrer cet objet vous-même dans le dossier de votre choix, puis modifier l'entrée de la base de données à la main.

Vous contourneriez l'ORM Django dans son ensemble, et ce n'est pas quelque chose que je ferais, à moins que je ne trouve plus de méthode Django.

+0

Je ne suis pas exactement sûr de ce que vous entendez par là. –

+0

Je viens de modifier toute la réponse pour la rendre plus claire. J'espère que cela aide. – voyager

3

Mon autre réponse est dépréciée, utilisez ceci:

class File(models.Model): 
    nzb = models.FileField(upload_to=get_filename) 
    ... 
    def get_filename(instance, filename): 
     if not instance.pk: 
      instance.save() 
     # Create the name slug. 
     name_slug = re.sub('[^a-zA-Z0-9]', '-', instance.name).strip('-').lower() 
     name_slug = re.sub('[-]+', '-', name_slug) 

     filename = u'filess/%(2)s_%(3)s.nzb' % {'2': instance.pk, '3': name_slug} 

     return filename 

A partir de 1,0, upload_to can be callable, auquel cas il devrait retourner le nom du fichier, y compris le chemin (par rapport à MEDIA_ROOT).

+0

Cela fonctionne plutôt bien, cependant, instance.save() renvoie cette erreur: "profondeur de récursivité maximale dépassée dans __instancecheck__". Savez-vous de quoi il s'agit? –

+0

Si le nom du fichier (ou, dans ce cas, name_slug) change et que le fichier n'est pas téléchargé à nouveau, le nom du fichier n'est pas modifié. Pas un gros problème, mais c'est ce que je cherchais. Ce devrait être encore plus propre, alors comment je le faisais avant. Savez-vous comment corriger cette erreur? –

+0

En outre, je ne pouvais le faire fonctionner que si "get_filename" était défini en dehors de la classe File, et au-dessus. –

Questions connexes