Home > Mobile >  How save space in HTML table when exporting to PDF Django / Python
How save space in HTML table when exporting to PDF Django / Python

Time:05-24

I have a very simple table that takes all employees working on one specific adress and returns me a list of names that looks like this:enter image description here

My question is how can i make the table fill the entire page so that instead of 3 pages or more i have 1 page with rows side by side to save space when printing.

The layout right now is

Page1: Name (break) Page2: Name (break) Page3: Name (break)

i want something like this: Page 1: Name | Name | Name (saving as much space without breaking page.)

The code i have tried using so far is this:

    <style type="text/css">
        @page {
            size: letter portrait;
            size: Letter;
            margin: 1.0cm;

        }

        body {
            font-size: 10pt;
        }

        . {
            padding: 4px;
        }

        table {
            border-collapse: collapse;
        }

        table,
        th,
        td,
        tr,{
          word-wrap:break-word;
          table-layout:fixed;
          border: 1px solid black;
          margin-top: 50%;
          text-align: left;
          padding: 8px;
        }

        .wrap {
            width: 50%;

        }

        .left_col {
            float: left;
            width: 48.4%;
        }

        .right_col {
            float: right;
            width: 50%;
        }
    </style>

</head>

<body style="margin-bottom:1px;">
<div>
    <h1>Jobsite: <b>{{location}}</b></h1>
    <h4>Date: <b>{{date}}</b></h4>
</div>


<table>
    <tr>
        <th>Name</th>
    </tr>

    {% for item in data %}
        <tr><td>{{forloop.counter}} - {{ item.LastFirst }}</tr></td>
    {% endfor %}

    <h5>Manager's Signature: _______________________________________</h5>
</table>


</body>

</html>

And this is where i handle the view:

@login_required()
def download_pdf(request, location_name):
    current = CurrentInfo()
    pdf_data = current.detail_employees_by_location(location_name)  # this gives me the list of people

    pf = pd.DataFrame.from_dict(pdf_data, orient='index', columns=['EmployeeNumber', 'LastFirst'])
    data = pf.drop_duplicates()
    count = data.count()
    data = data.to_dict('records')
    today = datetime.datetime.now()

    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="report.pdf"'
    html = render_to_string('user_area/template_download.html',
                            context={
                                'data': data,
                                'location': location_name,
                                'date': today
                            })

    pisa_status = pisa.CreatePDF(html, dest=response)

    if pisa_status.err:
        return HttpResponse('We had some errors <pre>'   html   '</pre>')
    return response

CodePudding user response:

Easiest solution I can up with is to put several td elements next to eachother. The forloop has several attributes as you noticed. We can use that for decision making. Note that I added a colspan=3 to the th to make it span all three columns.

Could not test the Django HTML code, so it could be slightly off ;)

<body style="margin-bottom:1px;">
<div>
    <h1>Jobsite: <b>{{location}}</b></h1>
    <h4>Date: <b>{{date}}</b></h4>
</div>
<table>
    <tr>
        <th colspan="3">Name</th>
    </tr> #changed the for loop to accept remainder operation.
    {% for item in data %}
        {% if forloop.first or forloop.counter0|divisibleby:"3"%}<tr>{%endif%}
            <td>{{forloop.counter}} - {{ item.LastFirst }}</td>
        {% if forloop.last or forloop.counter|divisibleby:"3"%}</tr>{%endif%}
    {% endfor %}
</table>
<h5>Manager's Signature: _______________________________________</h5>
</body>

Some explanation, I use two different versions of counter, the zero based and normal one. Reason is that I'm not 100% sure if Django template parses the 1 correctly otherwise. In python I'd do this:

In [2]: for i in range(100):
   ...:     if i==0 or i % 3 == 0:
   ...:         print('<tr>')
   ...:     print(i)
   ...:     if i==99 or (i   1) % 3 == 0:
   ...:         print('</tr>')

Output of this is similar to what I have in mind:

<tr>
0
1
2
</tr>
<tr>
3
4
5
</tr>
{% if forloop.first or forloop.counter0 % 3 == 0 %}<tr>{%endif%}

If it's the first iteration, or if it's a '3rd one': start a <tr>,

Similar, but for the closing tag:

{% if forloop.last or forloop.counter % 3 == 0 %}</tr>{%endif%}

If it's the last item, or it was a '3rd one', close the tr.

  • Related