Op woensdag 13 augustus 2014 15:00:38 UTC+2 schreef Anthony: > > def new_style_virtual_field_test(): > > db = DAL('sqlite:memory',pool_size=1) >> db.define_table('myorder', >> Field('a','integer'), >> Field('b','integer') >> ) >> db.myorder.c = Field.Virtual(lambda row:row.a * row.b) >> db.myorder.insert(a=2,b=3) >> return db().select(db.myorder.ALL).first().as_json() >> # {"a": 2, "id": 1, "b": 3} >> > > Are you sure that's the exact code you have run, because row.a * row.b is > not the correct syntax and should result in an exception as soon as you do > a select. >
It is, just tested this. I'm using 2.9.5-stable+timestamp.2014.03.16.02.35.39 using python 2.7.3 > Instead, it should be: > > db.myorder.c = Field.Virtual('c', lambda row: row.myorder.a * row.myorder.b) > > In the function, you must include the table name when accessing fields in > the row. Also, note that even when creating the virtual field via > assignment, you should still specify the name of the virtual field within > Field.Virtual() -- otherwise the "name" attribute of the virtual field will > be set to "unknown", which may cause problems in some contexts. > Thanks for the enlightenment. I've tried your change, and now it gives me the proper result. But i don't get your remark about the name attribute. I can't find that in the book for new style virtual classes, can you offer me a pointer? When looking at ">>> db.item.total_price = Field.Virtual(lambda row: row.unit_price*row.quantity)" from the book (mind the table name not being used here either) i thought the name assignment would be automatic by using db.myorder.c def new_style_virtual_field_test_anthony(): db = DAL('sqlite:memory',pool_size=1) db.define_table('myorder', Field('a','integer'), Field('b','integer') ) db.myorder.c = Field.Virtual(lambda row:row.myorder.a * row.myorder.b) # added tablenames in the lambda db.myorder.insert(a=2,b=3) return db().select(db.myorder.ALL).first().as_json() # {"a": 2, "c": 6, "b": 3, "id": 1} # hurray return db().select(db.myorder.a, db.myorder.b, >> db.myorder.c).first().as_json() >> # <class 'sqlite3.OperationalError'> no such column: None.unknown >> # (self=<gluon.dal.SQLiteAdapter object>, *a=('SELECT myorder.a, >> myorder.b, None.unknown FROM myorder;',), **b={}) >> >> # where has my C field gone to? >> > > Virtual fields are not stored in the database but are calculated after > records are pulled from the database, so they are not to be listed in the > call to .select(). > Can a notimplemented exception be justified in such a case? > def old_style_virtual_field_test1(): >> db = DAL('sqlite:memory',pool_size=1) >> db.define_table('myorder', >> Field('a','integer'), >> Field('b','integer') >> ) >> class MyVirtualFields(object): >> def c(self): >> return self.myorder.a * self.myorder.b >> db.myorder.virtualfields.append(MyVirtualFields()) >> db.myorder.insert(a=2,b=3) >> # return db().select(db.myorder.ALL).first().as_json() >> # {"a": 2, "id": 1, "b": 3} >> # where is c? >> > > Don't know. When I run the exact code above, I get: > > {"a": 2, "c": 6, "b": 3, "id": 1} > > My bad, i get the same. return db().select(db.myorder.a, db.myorder.b, >> db.myorder.c).first().as_json() >> # AttributeError: 'Table' object has no attribute 'c' >> >> # it doesn't ? I thought i declared to be virutally present >> > > Old style virtual fields work differently -- they don't result in > individual "field" attributes being added to the table object. Rather, they > are stored in the "virtualfields" attribute of the table. > def old_style_virtual_field_test1_anthony(): db = DAL('sqlite:memory',pool_size=1) db.define_table('myorder', Field('a','integer'), Field('b','integer') ) class MyVirtualFields(object): def c(self): return self.myorder.a * self.myorder.b db.myorder.virtualfields.append(MyVirtualFields()) db.myorder.insert(a=2,b=3) return db().select(db.myorder.a, db.myorder.b).first().as_json() # Don't include the virtual fields on .select, they're implied # {"a": 2, "c": 6, "b": 3} # hurray! I removed the db.myorder.c from the select and not it works. Above is the working sample left here for reference - this way it's basically the same as the above statement using old style virtual fields. > db.myorder.setvirtualfields(myorder=MyVirtualFields()) >> # <type 'exceptions.AttributeError'> 'Table' object has no attribute >> 'setvirtualfields' >> # maybe a bit more clarity in the documentation would be nice. I >> understand the purpose >> # but it's easily overlooked. >> > > The book seems fairly clear to me on this point. The only example it shows > using .setvirtualfields() is in the context of creating virtual fields on > the result of a join, with the following code: > > rows.setvirtualfields(order_item=MyVirtualFields()) > > It then says (highlights added): > > Notice how in this case the syntax is different. The virtual field > accesses both self.item.unit_price and self.order_item.quantity which > belong to the join select. The virtual field is attached to the rows of > the table using the setvirtualfields method of the rows object. > > As mentioned, it's easily overlooked but the documentation is complete. I'm not complaining or saying it's wrong, just letting a documentation writer in on some reader feedback. Thanks for your clarification here. > rows = db(db.myorder).select() >> # now i have to apply them after selecting? That's counter intuitive >> # i thought it would be in the model, not the controller >> rows.setvirtualfields(myorder=MyVirtualFields()) >> # also note the setvirtualfields has to be applied to the rows, not >> to a single row. >> > > There is no need to use .setvirtualfields() in the above example given > that you are selecting from a single table. The primary purpose of that > method is when you want to apply virtual fields to the result of a join of > multiple tables (so, you must apply the virtual fields to the rows rather > than to an individual table). > Indeed, that's why i was suprised. But i know understand more clearly what went wrong in the earlier examples, and would never use the code in the above example in such a case if something else is possible. Thank you Anthony. -- Resources: - http://web2py.com - http://web2py.com/book (Documentation) - http://github.com/web2py/web2py (Source code) - https://code.google.com/p/web2py/issues/list (Report Issues) --- You received this message because you are subscribed to the Google Groups "web2py-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to web2py+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.