ZipExtFile в файл Django - PullRequest
       1

ZipExtFile в файл Django

8 голосов
/ 22 декабря 2011

Мне интересно, есть ли способ загрузить zip-файл на веб-сервер django и поместить файлы 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.']}

[РЕШЕНИЕ] Решение с использованием уродливого хака:

Как правильно указал Дон Квест, файловые классы, такие как 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

Пожалуйста, продолжайте комментировать, если у вас есть лучшее решение (за исключением пользовательского хранилища)

Ответы [ 3 ]

7 голосов
/ 22 декабря 2011

Не зная многого о 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.

6 голосов
/ 20 августа 2012

Есть более простой способ сделать это:

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)
1 голос
/ 29 марта 2013

Я использовал следующий класс файлов 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...