Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate multiple PDFs and zip them for download, all in a single view

I am using xhtml2pdf to generate PDFs in my Django View. The idea is to loop over all the instances that are there in the query, then for each instance create a PDF, then add all the generated PDFs to one zip File for download. The xtml2pdf logic is working okay but the looping logic is what gives me headache.

So this is my function so far:

def bulk_cover_letter(request, ward_id, school_cat_id, cheque_number):
    school_type = SchoolType.objects.get(id=school_cat_id)

    schools_in_school_type = Applicant.objects.filter(
        school_type=school_type, ward_id=ward_id, award_status='awarded'
    ).order_by().values_list('school_name', flat=True).distinct()

    for school in schools_in_school_type:
        beneficiaries = Applicant.objects.filter(school_type=school_type, ward_id=ward_id, award_status='awarded', school_name=school)
        total_amount_to_beneficiaries = Applicant.objects.filter(school_type=school_type, ward_id=ward_id, award_status='awarded', school_name=school).aggregate(total=Sum('school_type__amount_allocated'))
        context = {
            'school_name' : school,
            'beneficiaries' : beneficiaries,
            'total_amount_to_beneficiaries' : total_amount_to_beneficiaries,
            'title' : school + ' Disbursement Details',
            'cheque_number': cheque_number
        }

        response = HttpResponse('<title>Cover Letter</title>', content_type='application/pdf')
        filename = "%s.pdf" %(cheque_number)
        content = "inline; filename=%s" %(filename)
        response['Content-Disposition'] = content
        template = get_template('cover_letter.html')
        html = template.render(context)
        result = io.BytesIO()
        pdf = pisa.CreatePDF(
            html, dest=response, link_callback=link_callback)
        if not pdf.error:
            # At this point I can generate a single PDF.
            # But no idea on what to do next.

    # The zipping logic should follow here after looping all the instances - (schools)

From that Point I have no idea on what to do next. Any help will be highly appreciated.

like image 541
Abedy Avatar asked Jan 11 '20 15:01

Abedy


People also ask

How do you create a multiple PDF zip file?

Select “Compressed (zipped) folder”. To place multiple files into a zip folder, select all of the files while hitting the Ctrl button. Then, right-click on one of the files, move your cursor over the “Send to” option and select “Compressed (zipped) folder”.

How to download multiple PDF files as ZIP format in browser?

Right-click this action method and select Go To View, where you will be directed to its associated view page Index.cshtml. Add new button in Index.cshtml as follows. Add a new action method named Download in HomeController.cs and include the following code snippet to download multiple PDF files as zip format in browser.

How to download multiple files as zip file using angular/SharePoint Online?

This article helps you to download multiple files as a zip file using Angular and SharePoint Online. Create a document library and upload the sample files in it. To create the zip file in Angular, the way we were required to for the js zip library file. To save the file on the client-side, we are required to file-save the library file.

How to compress PDF to zip?

You can use online compressors to ZIP PDF files. Here is a list of some online PDF compressors that save ZIP files in minutes. Step 1: Open the browser. Step 2: Navigate to your preferred tool, upload your chosen PDF file, and follow the prompt. How to Compress PDF Files Using Adobe Acrobat?

How do I split a PDF document into multiple pages?

In the Split Document dialog box, the default “Max pages” amount is 2, so change that to 1. (Note another handy tool in the Split Document feature set: instead of splitting up a PDF by page number, you could divvy it up into logical sections via bookmarks.


1 Answers

Try this:

Utils.py

def render_to_pdf(template_src, context_dict={}):
    template = get_template(template_src)
    html  = template.render(context_dict)
    buffer = BytesIO()
    p = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), buffer)
    pdf = buffer.getvalue()
    buffer.close()
    if not p.err:
        return pdf#HttpResponse(result.getvalue(), content_type='application/pdf')
    return None


def generate_zip(files):
    mem_zip = BytesIO()

    with zipfile.ZipFile(mem_zip, mode="w",compression=zipfile.ZIP_DEFLATED) as zf:
        for f in files:
            zf.writestr(f[0], f[1])

    return mem_zip.getvalue()

Views.py

def generate_attendance_pdf(modeladmin, request, queryset):

    template_path = 'student/pdf_template.html'

    files = []

    for q in queryset:
        context = {
            'firstname': q.firstname,
            'lastname': q.lastname,
            'p_firstname': q.bceID.firstname
        }
        pdf = render_to_pdf(template_path, context)
        files.append((q.firstname + ".pdf", pdf))

    full_zip_in_memory = generate_zip(files)

    response = HttpResponse(full_zip_in_memory, content_type='application/force-download')
    response['Content-Disposition'] = 'attachment; filename="{}"'.format('attendnace.zip')

    return response

Obviously, you have to modify the context/names to what you need.

Credit to -> Neil Grogan https://www.neilgrogan.com/py-bin-zip/

like image 155
Alvin Benedicto Avatar answered Oct 20 '22 09:10

Alvin Benedicto