2010-09-13 10 views
28

J'essaye d'attraper un fichier envoyé avec le formulaire et d'effectuer quelques opérations dessus avant qu'il ne soit sauvegardé. J'ai donc besoin de créer une copie de ce fichier dans le répertoire temporaire, mais je ne sais pas comment l'atteindre. Les fonctions de Shutil ne parviennent pas à copier ce fichier, car il n'y a pas de chemin. Alors, y a-t-il un moyen de faire cette opération d'une autre manière?Comment copier l'objet InMemoryUploadedFile sur le disque

Mon code:

image = form.cleaned_data['image'] 
    temp = os.path.join(settings.PROJECT_PATH, 'tmp') 
    sourceFile = image.name # without .name here it wasn't working either 
    import shutil 
    shutil.copy(sourceFile, temp) 

Ce qui soulève:

Exception Type: IOError at /
Exception Value: (2, 'No such file or directory')

Et le débogage:

# (..)\views.py in function 

    67. sourceFile = image.name 
    68. import shutil 
    69. shutil.copy2(sourceFile, temp) ... 

# (..)\Python26\lib\shutil.py in copy2 

    92. """Copy data and all stat info ("cp -p src dst"). 
    93. 
    94. The destination may be a directory. 
    95. 
    96. """ 
    97. if os.path.isdir(dst): 
    98. dst = os.path.join(dst, os.path.basename(src)) 
    99. copyfile(src, dst) ... 
100. copystat(src, dst) 
101. 

▼ Local vars 
Variable Value 
dst  
u'(..)\\tmp\\myfile.JPG' 
src  
u'myfile.JPG' 
# (..)\Python26\lib\shutil.py in copyfile 

    45. """Copy data from src to dst""" 
    46. if _samefile(src, dst): 
    47. raise Error, "`%s` and `%s` are the same file" % (src, dst) 
    48. 
    49. fsrc = None 
    50. fdst = None 
    51. try: 
    52. fsrc = open(src, 'rb') ... 
    53. fdst = open(dst, 'wb') 
    54. copyfileobj(fsrc, fdst) 
    55. finally: 
    56. if fdst: 
    57. fdst.close() 
    58. if fsrc: 

▼ Local vars 
Variable Value 
dst  
u'(..)\\tmp\\myfile.JPG' 
fdst  
None 
fsrc  
None 
src  
u'myfile.JPG' 

Répondre

39

This est question similaire, il pourrait aider.

import os 
from django.core.files.storage import default_storage 
from django.core.files.base import ContentFile 
from django.conf import settings 

data = request.FILES['image'] # or self.files['image'] in your form 

path = default_storage.save('tmp/somename.mp3', ContentFile(data.read())) 
tmp_file = os.path.join(settings.MEDIA_ROOT, path) 
+0

Hii, je pense codé en dur le "tmp/name.mp3" ce sera un problème dans le chemin multiplateforme, j'essaie d'améliorer votre code

 from django.conf import settings tmp = os.path.join(settings.MEDIA_ROOT, "tmp", data.name) path = default_storage.save(tmp, ContentFile(data.read()))

+2

Je n'aime pas ici ** data.read() ** –

+0

@ ups quel est le problème avec data.read() ?? –

5

Votre meilleur plan d'action est d'écrire un gestionnaire de chargement personnalisé. Voir le docs. Si vous ajoutez un gestionnaire "file_complete", vous pouvez accéder au contenu du fichier sans tenir compte d'un fichier de mémoire ou d'un fichier de chemin temporaire. Vous pouvez également utiliser la méthode "receive_data_chunck" et y écrire votre copie.

Cordialement

+0

Je l'utilisais pendant un certain temps jusqu'à ce qu'un nom en double soit téléchargé et que django ajoute automatiquement un suffixe pour rendre le nom de fichier unique. Ce nom de fichier renommé n'était pas disponible au niveau du gestionnaire de téléchargement. A part ça, cela a fonctionné très proprement. – awwester

1

Voici une autre façon de le faire avec mkstemp de python:

### get the inmemory file 
data = request.FILES.get('file') # get the file from the curl 

### write the data to a temp file 
tup = tempfile.mkstemp() # make a tmp file 
f = os.fdopen(tup[0], 'w') # open the tmp file for writing 
f.write(data.read()) # write the tmp file 
f.close() 

### return the path of the file 
filepath = tup[1] # get the filepath 
return filepath 
7

Comme mentionné par @ups, lors du téléchargement de gros fichiers, vous ne voulez pas encombrer la mémoire système avec un data.read().

De Django docs:

Looping over UploadedFile.chunks() instead of using read() ensures that large files don't overwhelm your system's memory

from django.core.files.storage import default_storage 

filename = "whatever.xyz" # received file name 
file_obj = request.data['file'] 

with default_storage.open('tmp/'+filename, 'wb+') as destination: 
    for chunk in file_obj.chunks(): 
     destination.write(chunk) 

Cela permettra d'économiser le fichier à MEDIA_ROOT/tmp/ que votre default_storage volonté à moins d'avis contraire.

+0

Comme ceci, j'obtiens: FileNotFoundError: [Errno 2] Aucun fichier ou répertoire: '// .png'. Des idées? – Daviddd

+0

@Daviddd le fichier n'est pas là où vous pensez qu'il est, et ce n'est pas pertinent pour ce code. –