generating tables using mako templates
May 22, 2009 4:01 AM Subscribe
Using a Mako template and CSS, I need to generate a m x n grid display from a variable length list of elements.
For simplicity's sake, let's say what I want is a 2 x n table, but I'm fine with unordered lists as long as they appear on screen aligned as if they were in rows and columns.
What does the logic look like in mako to create such a structure? I'm having trouble figuring out when to start a new row or close and old one, while still keeping the template simple and readable.
Please spell things out and use small words as I'm new to both Mako and CSS (but somewhat conversant in Python), and keep me from the temptation to hard-code a solution for a fixed length list of elements.
For simplicity's sake, let's say what I want is a 2 x n table, but I'm fine with unordered lists as long as they appear on screen aligned as if they were in rows and columns.
What does the logic look like in mako to create such a structure? I'm having trouble figuring out when to start a new row or close and old one, while still keeping the template simple and readable.
Please spell things out and use small words as I'm new to both Mako and CSS (but somewhat conversant in Python), and keep me from the temptation to hard-code a solution for a fixed length list of elements.
Metafilter ate my first code block. Worked in live preview!
posted by pengale at 6:29 AM on May 22, 2009
<%! from foo import split_into_cols COLS = 2 %>
posted by pengale at 6:29 AM on May 22, 2009
Don't be afraid of using HTML tables. You are, after all, displaying a table of data.
posted by zsazsa at 9:23 AM on May 22, 2009
posted by zsazsa at 9:23 AM on May 22, 2009
Using only CSS it is pretty easy to get this style output from a single list:
1,2,3
4,5,6
7,8,9
And there are a variety of client-side tricks to get the more common:
1,4,7
2,5,8
3,6,9
You can see some options explored at A List Apart: CSS Swag: Multi-Column Lists
The quick test to decide if data is tabular is think up names for the rows and columns. If you have to use artificial labels like "first third of the names" then you probably have a list not a table.
posted by samsm at 9:54 AM on May 22, 2009
1,2,3
4,5,6
7,8,9
And there are a variety of client-side tricks to get the more common:
1,4,7
2,5,8
3,6,9
You can see some options explored at A List Apart: CSS Swag: Multi-Column Lists
The quick test to decide if data is tabular is think up names for the rows and columns. If you have to use artificial labels like "first third of the names" then you probably have a list not a table.
posted by samsm at 9:54 AM on May 22, 2009
Response by poster: Could you give me an example of a list and the output you expect?
Sure.
list = [a b c d e f]
Display:
a b
c d
e f
The code I currently have shows the items in a single column display. I just want to show more than one item per row.
I do not have the sort of information that requires row headings and column headings - it's not a true table - I just want to lay out the data on screen in a denser way than a straight unordered list, while maintaining some visual order in the layout.
The actual contents of each cell (a, b, etc.) are a thumbnail image and a line of text. In the output I would like to maintain visual balance for each cell. Specifically I want to constrict how much horizontal space the text can occupy, so that it flows next to the thumbnail.
Here's my existing code:
posted by zippy at 11:51 AM on May 22, 2009
Sure.
list = [a b c d e f]
Display:
a b
c d
e f
The code I currently have shows the items in a single column display. I just want to show more than one item per row.
I do not have the sort of information that requires row headings and column headings - it's not a true table - I just want to lay out the data on screen in a denser way than a straight unordered list, while maintaining some visual order in the layout.
The actual contents of each cell (a, b, etc.) are a thumbnail image and a line of text. In the output I would like to maintain visual balance for each cell. Specifically I want to constrict how much horizontal space the text can occupy, so that it flows next to the thumbnail.
Here's my existing code:
<table cellspacing="0" cellpadding="0" border="0">
<tr class="b">
% for result in results:
<td class="b">
<td>
<%call expr="self.link(result)">
<img src="${result['thumbnail'] | h}" border="0">
</%call>
</td>
<td>
<%call expr="self.link(result)">${h.truncate(result['name'], length=25) | h}</%call>
</td>
</td>
% endfor
</tr>
</table>
posted by zippy at 11:51 AM on May 22, 2009
Best answer: I initially misunderstood your intention: I thought you wanted them grouped by columns rather than by rows.
If you want the individual items to be of fixed size, you could use CSS and do this without a table. Just give each item
If you want to split the list in Python, a list comprehension would work fine.
posted by pengale at 12:55 PM on May 22, 2009
If you want the individual items to be of fixed size, you could use CSS and do this without a table. Just give each item
display: block; float: left; overflow:hidden;
and a fixed width and height, (or width: 49.5%
for two columns) and put them into a container that is sized so they wrap the way you want. This could cause problems if your text overflows and is truncated, but I see you're already limiting the length of the text.If you want to split the list in Python, a list comprehension would work fine.
my_list = range(21) # sample data COLS = 2 num_rows = (len(my_list) + COLS - 1) / COLS out_list = [my_list[x * COLS:(x + 1) * COLS] for x in xrange(num_rows)]Then use nested for loops (the output is a list of lists that in this case goes [[1,2],[3,4]...]) and structure the HTML however you want.
posted by pengale at 12:55 PM on May 22, 2009
This thread is closed to new comments.
Either way, I would split the list into rows or columns first, then use a simple nested for loop over the resulting data structure.
Assuming this is purely a "display" thing (i.e. not part of domain logic at all) and that you might want to alter the number of columns just by editing the template, I'd define a function to do the list-splitting and then call it from your template. You can import modules in code blocks inside templates, something like: Then, later: If you want to use unordered lists, you'll furthermore need to play around with the CSS till you get the look you want. The general way to do this would be to give the lists
float: left
and awidth
in either pixels or percent, and put a div withclear:left
at the bottom and/or enclose them in a container withfloat: left; width: 100%;
. Hard to say without knowing what "look" you want. Since you said "grid" in your post, you might prefer a table.posted by pengale at 6:28 AM on May 22, 2009