Django: создайте zip-файл из S3 с помощью django-storage

#python #django #amazon-s3 #boto3 #django-storage

#python #django #amazon-s3 #boto3 #django-storage

Вопрос:

Я использую django-storages, и пользовательский контент хранится в папках на S3. Теперь я хочу, чтобы пользователи имели возможность загружать все свои файлы сразу, предпочтительно в zip-файле. Все предыдущие сообщения, связанные с этим, устарели или не работают для меня.

Самый близкий к рабочему код, который у меня есть на данный момент:

 from io import BytesIO
import zipfile
from django.conf import settings
from ..models import Something
from django.core.files.storage import default_storage

class DownloadIncomeTaxFiles(View):

    def get(self, request, id):
        itr = Something.objects.get(id=id)
        files = itr.attachments
        zfname = 'somezip.zip'
        b =  BytesIO()
        with zipfile.ZipFile(b, 'w') as zf:
            for current_file in files:
                try:
                    fh = default_storage.open(current_file.file.name, "r")
                    zf.writestr(fh.name, bytes(fh.read()))
                except Exception as e:
                    print(e)
            response = HttpResponse(zf, content_type="application/x-zip-compressed")
            response['Content-Disposition'] = 'attachment; filename={}'.format(zfname)
            return response
  

Это создает то, что выглядит как zip-файл, но единственным содержимым, которое у него есть, является ‘<zipfile.ZIP-файл [закрыт]>’

Я получил много разных результатов, в основном с ошибками, такими как zipfile, ожидающий содержимого строки или байтов при предоставлении файла FieldFile. На данный момент я полностью застрял.

Ответ №1:

Проблема заключалась в том, что мне нужно было вернуться к началу файла, добавив

 zf.seek(0)
  

непосредственно перед возвратом файла в HttpResponse.

Ответ №2:

Здесь есть 2 проблемы. первое заключается в том, что, даже если вы создаете zip-файл, вы записываете данные в объект bytesio, и второе, вам нужно навести курсор в начале, поскольку writer будет указывать на конец. Так что это должно быть:

 b.seek(0)
response = HttpResponse(b, content_type="application/x-zip-compressed")