繁体   English   中英

ZipExtFile到Django文件

[英]ZipExtFile to Django File

我想知道是否有办法将zip文件上传到django web服务器并将zip文件放入django数据库而不访问过程中的实际文件系统(例如将zip文件解压缩到tmp目录然后加载它们)

Django提供了一个将python文件转换为Django文件的函数,所以如果有一种方法将ZipExtFile转换为python文件,它应该没问题。

感谢帮助!

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.']}

[解决方案]解决方案使用丑陋的黑客:

正如Don Quest正确指出的那样,类似文件的类(如StringIO或BytesIO)应将数据表示为虚拟文件。 但是,Django File的构造函数只接受内置文件类型而不接受任何其他内容,尽管类文件类也可以完成这项工作。 黑客是手动设置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的情况下,我可以告诉你看一下“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 Stream / File做任何你想做的事情。

有一种更简单的方法:

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文件。 有关更完整的示例,假设您要将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)

我使用了以下django文件类,以避免需要将ZipExtFile读入另一个数据结构(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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM