Best Practice for picture layout

1 view
Skip to first unread message

David Xiao

unread,
Dec 4, 2006, 7:42:37 AM12/4/06
to TurboGears
Hello there,

I am just trying to write a demostration web page which list a number
of small pictures.
I want it be prgrammable in row and columns.

Suppose i write following line in controller.py
def viewall(self):
pics = [pics for pics in
Pictures.select(orderBy=Pictures.q.shortname)]
return dict(pics=pics, column=4, max_row=4)

I actually find some code that can show each picture in a seperate DIV,
that's look good. But i was not able to "glue" those code into KID
template. So for me, the problem might be: How should I wrote code in
.KID template to represent these pictures' shortname in a table (column
and max_rows), accordingly?


Regards
David

davi...@gmail.com

unread,
Dec 4, 2006, 1:35:50 PM12/4/06
to TurboGears
Couple of things I'd suggest here:

1. Don't use a list comprehension in this case. It's not necessary.
Pictures.select already returns an iterable SQLResults collection; you
can iterate over that in your Kid template and save some time. Just
do:

pics = Pictures.select(orderBy='shortname')

BTW, orderBy takes a string, not a database column.

2. As for the Kid template, your basic idea will be:

<ul py:if="pics">
<li py:for="pic in pics">
<img src="${pic.src}" alt="${pic.alt}" height="${pic.height}"
width="${pic.width}" />
</li>
</ul>

The rest is up to you and your command of HTML and CSS.

Good luck,
David

Diez B. Roggisch

unread,
Dec 4, 2006, 1:46:03 PM12/4/06
to turbo...@googlegroups.com
On Monday 04 December 2006 19:35, davi...@gmail.com wrote:
> Couple of things I'd suggest here:
>
> 1. Don't use a list comprehension in this case. It's not necessary.
> Pictures.select already returns an iterable SQLResults collection; you
> can iterate over that in your Kid template and save some time. Just
> do:
>
> pics = Pictures.select(orderBy='shortname')
>
> BTW, orderBy takes a string, not a database column.

It takes both, the latter is especially important when you try and sort after
a joined object/table.

Diez

davi...@gmail.com

unread,
Dec 4, 2006, 1:58:19 PM12/4/06
to TurboGears
Good point. I'd've found that if I'd read the docs more closely.
Thanks!

David

Joost Moesker

unread,
Dec 4, 2006, 2:06:28 PM12/4/06
to TurboGears
The 'grouper' example in the python docs chapter 6.5.3 (itertools
section) can be usefull if you need to chop a iterable into small fixed
sized chunks ( eg. rows).

def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'),
('g','x','x')"
return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)

David Xiao

unread,
Dec 6, 2006, 8:31:39 AM12/6/06
to TurboGears
I am not quite understand how to generate KID template in that way.
For example, pics = Pictures.select(orderBy='shortname') returns 5
results, and I want the HTML code look like, 2 elements per row:
<table>
<tr>
<td>result 1</td>
<td>result 2</td>
</tr>
<tr>
<td>result 3</td>
<td>result 4</td>
</tr>
<tr>
<td>result 5</td>
<td></td>
</tr>
</table>

How should I write .kid template code?

Christoph Zwerschke

unread,
Dec 6, 2006, 9:05:09 AM12/6/06
to turbo...@googlegroups.com

You can try something like this:

<tr py:for="i in range((len(pics)+1)//2)">
<td><img src="${pics[2*i]}" /></td>
<td><img py:if="len(pics)>2*i+1" src="${pics[2*i+1]}" /></td>
</tr>

-- Christoph

Paul Johnston

unread,
Dec 6, 2006, 9:09:49 AM12/6/06
to turbo...@googlegroups.com
Hi,

One approach is like this:

<tr py:for="i in range(0, len(pics), 2)">
<td>${pics.get(i)}</td>
<td>${pics.get(i+1)}</td>
</tr>

There is probably a neater way of doing this using some of Python's funky iteration tools. Note that above you must use pics.get, not pics[] in case there is an odd number of pics.

Enjoy,

Paul

Christoph Zwerschke

unread,
Dec 6, 2006, 9:43:50 AM12/6/06
to turbo...@googlegroups.com
Christoph Zwerschke wrote:
> <tr py:for="i in range((len(pics)+1)//2)">
> <td><img src="${pics[2*i]}" /></td>
> <td><img py:if="len(pics)>2*i+1" src="${pics[2*i+1]}" /></td>
> </tr>

Sorry, that was a bit unpythonic. Using the step parameter of range as
suggested by Paul is better:

<tr py:for="i in range(0, len(pics), 2)">
<td><img src="${pics[i]}" /></td>
<td><img py:if="len(pics)>i+1" src="${pics[i+1]}" /></td>
</tr>

Here is a solution for an arbitrary number of cols:

<table py:if="pics">
<tr py:for="i in range(0, len(pics), cols)">
<td py:for="j in range(cols)">
<img py:if="len(pics)>i+j" src="${pics[i+j]}" />
</td>
</tr>
</table>

Ed Singleton

unread,
Dec 6, 2006, 9:46:42 AM12/6/06
to turbo...@googlegroups.com

Well you want to send a list of tuples to your template, where each
tuple has two pictures in it. Then you just iterate through that.

Using the grouper example someone else posted, I would guess something
like this might work:

in controller:

pics = izip(*[chain(Pictures.select(orderBy=Pictures.q.shortname),
repeat('', 1))]*2)

in template:

<tr py:for="pic1, pic2 in pics">
<td>$pic1</td>
<td>$pic2</td>
</tr>

This is entirely untested but should give you an idea.

Ed

David Xiao

unread,
Dec 6, 2006, 10:16:54 AM12/6/06
to TurboGears
I receive following error: TypeError: len() of unsized object
I am quite sure that pics is with results, it's not empty. I guess
maybe there should be another function to test iterable list's
length(), but what could be?

David Xiao

unread,
Dec 6, 2006, 10:30:11 AM12/6/06
to TurboGears
Moreover, i tried replace len() with a number, and receive another
error from the code snippet:
UnboundLocalError: local variable 'i' referenced before assignment

I am new to Python and Turbogears, so appreciate your further help.

Christoph Zwerschke

unread,
Dec 6, 2006, 10:56:18 AM12/6/06
to turbo...@googlegroups.com

For simplicity I assumed "pics" is just a list of URLs. If you have a
SQLObject SelectResult, you need to convert it to such a list first,
using something like:

pics = [p.url for p in pics]

Or, if you want to use the SelectResult directly you can determine the
number of pics as pics.count() instead of using len(pics). Then you will
probably have to write something like pics[i].url instead of pics[i].

Reply all
Reply to author
Forward
0 new messages