Kirill
Kirill

Reputation: 173

Can't open zip file created with python and Django

I create a set of pdf files and want to add them to zip archive. Everything seems fine, but when I download my zip file It can't be open.

So I create pdf with create_pdf function

def create_pdf(child):
    buffer = io.BytesIO()
    canvas = Canvas(buffer, pagesize=A4)
    p = staticfiles_storage.path('TNR.ttf')
    pdfmetrics.registerFont(TTFont('TNR', p))
    canvas.setFont('TNR', 14)
    t = canvas.beginText(-1 * cm, 29.7 * cm - 1 * cm)
    t.textLines(create_text(child), trim=0)

    canvas.drawText(t)
    canvas.save()
    pdf = buffer.getvalue()
    return pdf

Then I create zip file and pack it to response

def create_zip(pdfs):
    mem_zip = io.BytesIO()
    i = 0
    with zipfile.ZipFile(mem_zip, mode='w', compression=zipfile.ZIP_DEFLATED)\
         as zf:
        for f in pdfs:
            i += 1
            zf.writestr(f'{str(i)}.pdf', f)
    return mem_zip.getvalue()


def get_files(request, children):
    pdfs = []
    for child in children:
        pdfs.append(create_pdf(child))
    zip = create_zip(pdfs)
    response = FileResponse(zip,
                            content_type='application/zip',
                            filename='zayavleniya.zip')
    response['Content-Disposition'] = 'attachment; filename=files.zip'
    return response

Please help to find where I am wrong.

Upvotes: 0

Views: 604

Answers (2)

olinox14
olinox14

Reputation: 6653

In the documentation, you can see the write_str method expects data as second argument. Here, you are providing a filename. So the content of the pdf files are just "i.pdf", which is of course not the content that you expect for a pdf file.

Try with something like this:

def create_zip(pdfs):
    mem_zip = io.BytesIO()
    i = 0
    with zipfile.ZipFile(mem_zip, mode='w', compression=zipfile.ZIP_DEFLATED)\
         as zf:
        for filename in pdfs:
            i += 1
            with open(filename, 'rb') as f:
                zf.writestr(f'{i}.png', f.read())
    return mem_zip.getvalue()

NB: try to avoid using zip as a variable name, since it is already a builtin python function

Update

If you isolate the archive creation to get a minimal working example, you get this, which create an zipfile as you wanted:

def create_zip(pdfs):
    i = 0
    with zipfile.ZipFile(HERE / "my_archive.zip", mode='w', compression=zipfile.ZIP_DEFLATED)\
         as zf:
        for filename in pdfs:
            i += 1
            with open(filename, 'rb') as f:
                zf.writestr(f'{str(i)}.png', f.read())

create_zip(["icon.png"])

Upvotes: 1

Kirill
Kirill

Reputation: 173

After I post this question I managed to find the answer myself. I changed create_zip

def create_zip(pdfs):
    mem_zip = io.BytesIO()
    i = 0
    with zipfile.ZipFile(mem_zip, mode='w', compression=zipfile.ZIP_DEFLATED)\
         as zf:
        for f in pdfs:
            i += 1
            zf.writestr(f'{str(i)}.pdf', f)
    mem_zip.seek(0)
    return mem_zip

Upvotes: 0

Related Questions