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.

Reply via email to