2011-12-22 20 views
7

私は、django Webサーバーにzipファイルをアップロードし、そのプロセスで実際のファイルシステムにアクセスすることなくzipファイルをdjangoデータベースに入れる方法があるかどうか疑問に思っています。 tmpディレクトリをロードしてからロードしてください)ZipExtFile to Djangoファイル

DjangoはPythonファイルをDjangoファイルに変換する機能を提供しています。そのため、ZipExtFileをPython Fileに変換する方法があれば問題ありません。

助けてくれてありがとう!

Djangoのモデル:

from django.db import models 

class Foo: 
    file = models.FileField(upload_to='somewhere') 

は使用方法:

from zipfile import ZipFile 
from django.core.exceptions import ValidationError 
from django.core.files import File 
from io import BytesIO 

z = ZipFile('zipFile') 
istream = z.open('subfile') 
ostream = BytesIO(istream.read()) 
tmp = Foo(file=File(ostream)) 
try: 
    tmp.full_clean() 
except Validation, e: 
    print e 

出力:

{'file': [u'This field cannot be blank.']} 

[SOLUTION]ソリューション醜いハックを使用して:として正しくによって指摘

ドンクエスト、ファイルのようなクラスStringIOやBytesIOのようなものは、データを仮想ファイルとして表現する必要があります。しかし、Django Fileのコンストラクタは、組み込みファイルの種類だけを受け付けますが、それ以外のものは受け付けませんが、ファイルのようなクラスでも同様に処理が行われます。

buf = bytesarray(OPENED_ZIP_OBJECT.read(FILE_NAME)) 
tmp_file = BytesIO(buf) 
dummy_file = File(tmp_file) # this line actually fails 
dummy_file.name = SOME_RANDOM_NAME 
dummy_file.size = len(buf) 
dummy_file.file = tmp_file 
# dummy file is now valid 

あなたは(独自のストレージを除く)より良い解決策を持っている場合はDjangoについて多くを知らないコメント

+0

あなたがカスタムファイルストレージを使用しない限り、ファイルはまだファイルシステムにヒットしますが、Donは適切なアイデアを持っています。 –

+0

https://docs.djangoproject.com/en/dev/howto/custom-file-storage/ – tkone

+1

答えに感謝します。しかし、私は簡単にzipファイルを保存することができ、zipファイルのファイルは元のzipファイルと同じにする必要があるので、なぜこれが直接動作しないのか分かりません。答えのために – guinny

答えて

6

を保管してください、私が言うことができる:ハックはジャンゴで変数を設定する::ファイルを手動であなたは "io"パッケージを見てください。 あなたのような何かを行うことができます:

from zipfile import ZipFile 
from io import StringIO 
zname,zipextfile = 'zipcontainer.zip', 'file_in_archive' 
istream = ZipFile(zname).open(zipextfile) 
ostream = StringIO(istream.read()) 

をそして、あなたはあなたの「仮想」のostreamストリーム/ファイルをどうしたいものは何でも。

from django.core.files.base import ContentFile 

uploaded_zip = zipfile.ZipFile(uploaded_file, 'r') # ZipFile 

for filename in uploaded_zip.namelist(): 
    with uploaded_zip.open(filename) as f: # ZipExtFile 
     my_django_file = ContentFile(f.read()) 

、あなたはDjangoのファイルに直接メモリにアップロードされたファイルを変換することができ、これを使用する:

+0

ありがとう。しかし、istream.read()は文字列の代わりにバイト配列を返します。そして、私はバイトをデコードすることはできません。イメージを表すからです。 – guinny

+0

はい、それは私が試したものでした。プログラムはエラーを発生させませんが、DjangoはBytesIOをdjango.fileに変換する際に問題があります... – guinny

+0

問題ありません!代わりにByteIOを使用してください:http://docs.python.org/library/io.htmlを参照してください。詳細については、highlight = io#を参照してください。 –

6

は、これを行うための簡単な方法があります。より完全な例については、あなたがファイルシステムへのzipの内部の画像ファイルのシリーズをアップロードしたいとしましょう:

# some_app/models.py 
class Photo(models.Model): 
    image = models.ImageField(upload_to='some/upload/path') 

... 

# Upload code  
from some_app.models import Photo 

for filename in uploaded_zip.namelist(): 
    with uploaded_zip.open(filename) as f: # ZipExtFile 
     new_photo = Photo() 
     new_photo.image.save(filename, ContentFile(f.read(), save=True) 
0

私はZipExtFileに読み込みする必要性を回避するために、次のDjangoのファイルクラスを使用しました別のデータ構造(StingIOまたはBytesIO)を使用して、ファイルを直接保存するためにDjangoが必要とするものを適切に実装します。

from django.core.files.base import File 

class DjangoZipExtFile(File): 
    def __init__(self, zipextfile, zipinfo): 
     self.file = zipextfile 
     self.zipinfo = zipinfo 
     self.mode = 'r' 
     self.name = zipinfo.filename 
     self._size = zipinfo.file_size 

    def seek(self, position): 
     if position != 0: 
      #this will raise an unsupported operation 
      return self.file.seek(position) 
     #TODO if we have already done a read, reopen file 

zipextfile = archive.open(path, 'r') 
zipinfo = archive.getinfo(path) 
djangofile = DjangoZipExtFile(zipextfile, zipinfo) 
storage = DefaultStorage() 
result = storage.save(djangofile.name, djangofile) 
関連する問題