web-dev-qa-db-fra.com

Comment copier un objet InMemoryUploadedFile sur le disque

J'essaie d'attraper un fichier envoyé avec le formulaire et d'effectuer certaines opérations dessus avant qu'il ne soit enregistré. J'ai donc besoin de créer une copie de ce fichier dans le répertoire temp, mais je ne sais pas comment y accéder. Les fonctions de Shutil ne parviennent pas à copier ce fichier, car il n'y a aucun chemin d'accès. Existe-t-il un moyen de faire cette opération d'une autre manière?

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'
37
sasklacz

This est une question similaire, cela 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)
48
Davor Lucic

Comme mentionné par @ Sławomir Lenart , lors du téléchargement de gros fichiers, vous ne voulez pas obstruer la mémoire système avec une data.read().

De documents Django :

Faire une boucle sur UploadedFile.chunks() au lieu d'utiliser read() garantit que les fichiers volumineux ne surchargent pas la mémoire de votre système

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 enregistrera le fichier à MEDIA_ROOT/tmp/ comme votre default_storage le fera sauf indication contraire.

15
Emile Bergeron

La meilleure solution consiste à écrire un gestionnaire de téléchargement personnalisé. Voir docs . Si vous ajoutez un gestionnaire "file_complete", vous pouvez accéder au contenu du fichier indépendamment de la présence d'un fichier 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

5
Arthur Debert

Voici une autre façon de le faire avec le 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
4
David542