I see what is going on:
>>> db=SQLDB()
>>> db.define_table('book',SQLField('title'),SQLField('author'))
>>> db.book.insert(title='web2py',author='Massimo')
1
>>> rows=db().select(db.book.id,db.book.title,db.book.author)
>>> print rows.colnames
('book.id', 'book.title', 'book.author')
>>> for row in rows: print row
<SQLStorage {'update_record': <function <lambda> at 0x250b0f0>, 'author': 'Massimo', 'id': 1, 'title': 'web2py'}>
>>> rows.colnames=('ID','TITLE','AUTHOR')
>>> print rows.xml()
<table><thead><tr><th>ID</th><th>TITLE</th><th>AUTHOR</th></tr></thead><tbody><tr class="even"><td>1</td><td>web2py</td><td>Massimo</td></tr></tbody></table>
>>> for row in rows: print row
<SQLStorage {'_extra': <SQLStorage {'AUTHOR': 'Massimo', 'ID': 1, 'TITLE': 'web2py'}>}>
Changing row.colnames changes the way to retrieve columns when you change colnames. Bad.
I take back my suggestion about changing colnames to change the column names. DO NOT DO IT. There is a better and cleaner way:
Instead of simply printing {{=rows}}, print {{=SQLTABLE(rows,headers=headers)}} instead where headers is a dictionary you define that looks like this:
headers={'book.author':'Author'}
the headers names in the dictionary will be renamed accordingly.
Massimo