[英]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.