I am investigating this area for quite time https://docs.google.com/document/d/1ZOwRUJz4gRPI875rftTfwOBIera1JgZDPulooGjNyu0/edit?hl=en_US
you can choose from a few models, but my idea is to preload all rows in controller then to pass them to view in controller: #OrderedTree rows = db(db.tree_table).select(orderby=db.tree_table.line) #Nested Sets rows = db(db.tree_table).select(orderby=db.tree_table.left) #AdjacencyList rows = get_recursive_all_items(#here goes your recursive function to get all items) also I assume that item level is precomputed and is 0 based in view: <style> .category{ padding-left: 20px; border:1px solid #aaaaaa; } </style> {{last_level=0}} {{for row in rows:}} {{if row.level<last_level:}} {{=XML('</div>'*(last_level-row.level))}} {{pass}} {{if row.level>last_level:}} <div class="category"> {{pass}} <div>{{=row.item_data}}</div> {{last_level = row.level}} {{pass}} {{=XML('</div>'*(last_level))}}