The docs for lazy virtual fields (http://web2py.com/book/default/ chapter/06#Virtual-Fields) give incorrect results; the virtual field is incorrectly mapped to the last row selected in certain cases.
Here's a sample: class table_story_titleAsSlug(object): def titleAsSlug(self): def lazy(self=self): return urls.convert_to_slug(self.story.title) return lazy db.story.virtualfields.append(table_story_titleAsSlug()) titleAsSlug() will always return the value for the last row selected from stories. While this may not apply in all cases, I've found a fix: class table_story_titleAsSlug(object): def titleAsSlug(self): def lazy(title=self.story.title): return urls.convert_to_slug(title) return lazy db.story.virtualfields.append(table_story_titleAsSlug()) Notes: In the debugger, the second self always refers to one instance of table_story_titleAsSlug, which explains why self.story.title gets overwritten. Are virtual field objects like table_story_titleAsSlug only instantiated once?