HTML Tables with Yattag - creating new TR

3.1k views Asked by At

I use yattag to create HTML, and in my code, I want to loop over database records, and, dynamically, creating HTML tables.

For example, if the number of divs in the is 5 :

with tag('table', klass='all-pr'):
        with tag('tr'):
            with tag('td'):
                for zone in all_zones:
                    clear += 1
                    with tag('div', klass='pr' + ' ' + risk_alert):
                        text(zone['name'])
                    with tag('div', klass='link-pr'):
                        text('-')
                    if (clear % 5 == 0):
                        # create a new <tr>

Update : ok, the html I expect is :

<table class="all-pr" >
 <tr>
    <td> 
        <div class="pr risk-alert-high">114</div>
        <div class="link-pr">-</div>
        <div class="pr risk-alert-high">115</div>
        <div class="link-pr">-</div>
        <div class="pr risk-alert-high">116</div>
        <div class="link-pr">-</div>
        <div class="pr risk-alert-high">117</div>
        <div class="link-pr">-</div>
        <div class="pr risk-alert-high">118</div>
        <div class="link-pr">-</div>
    </td>    
 </tr>
 <!-- BREAK HERE -->
 <tr>
    <td> 
        <div class="pr risk-alert-high">119</div>
        <div class="link-pr">-</div>
        <div class="pr risk-alert-high">120</div>
        <div class="link-pr">-</div>
        <div class="pr risk-alert-high">121</div>
        <div class="link-pr">-</div>
        <div class="pr risk-alert-high">122</div>
        <div class="link-pr">-</div>
        <div class="pr risk-alert-high">123</div>
        <div class="link-pr">-</div>
    </td>    
 </tr>
    ...
    ...
 </table> 

The (part of) CSS :

.link-pk, .pr {
    text-align: center;
    float: left;
    margin-top: 5px;
    padding: 5px;
    width : 25px
}

And, after, I convert the HTML in PDF with PDFKIT lib.

But I don't know how to close a tag and (re)create new one, and go on with the loop... Any idea ?

Thanks, F.

1

There are 1 answers

0
John Smith Optional On

So the problem is not really about Yattag, right? Your problem is to take the elements by groups of 5 (or whatever fixed number). For this I'd use the islice method from the itertools module.

You have an example of how to use this function to create a take function that takes the first n elements of an iterable:

https://docs.python.org/3/library/itertools.html#itertools-recipes

Using this take function, you can consume an iterable by groups of n elements. Here's the solution to your particular problem:

from itertools import islice
from yattag import Doc, indent

def take(n, iterable):
    "Return first n items of the iterable as a list"
    return list(islice(iterable, n))

def zones_to_html(zones):
    zones_iterator = iter(zones) # in case zones is not already an iterator
    doc, tag, text, line = Doc().ttl()
    with tag('table', klass="all-pr"):
        while True:
            first5 = take(5, zones_iterator)
            if len(first5) == 0:
                break
            else:
                with tag('tr'):
                    with tag('td'):
                        for zone in first5:
                            line('div', zone['name'], klass = 'pr ' + zone['risk_alert'])
                            line('div', '-', klass='link-pr')
    return doc.getvalue()

# Example of use:
if __name__ == '__main__':
    all_zones = ({'name': i, 'risk_alert': 'high'} for i in range(114, 129))
    print(indent(zones_to_html(all_zones)))

I used the line method of Yattag, which is a shortcut described here: http://www.yattag.org/#shortcut-for-nodes-that-contain-only-text