GAE update_record() has subtle difference compared to native Web2Py

20 views
Skip to first unread message

Carl

unread,
Feb 3, 2010, 7:59:52 AM2/3/10
to web2py-users
Given:
- a define_table() with a field as "compute=lambda r:r['name'].lower
()"
- that I call update_record() on a row returned from a select.

when I test on dev_appserver I need to include name as a parameter to
update_record() otherwise an exception is thrown by Set.update(self,
**update_fields) in gql.py (line 696)

I post this for the record for anyone using GAE and update_record()
rather than a call to action.

I'm using Web2py 1.74.6

mdipierro

unread,
Feb 3, 2010, 10:51:31 AM2/3/10
to web2py-users
what is the traceback?

Carl

unread,
Feb 3, 2010, 11:59:25 AM2/3/10
to web2py-users

MainThread - pid4460_seq4
update [gql.py:696]
update_record [sql.py:3232]
<lambda> [sql.py:3109]
update [subscription.py:65]
update_team [default.py:call:68]
serve_jsonrpc [tools.py:2560]
__call__ [tools.py:2646]
call [default.py:call:594]
<lambda> [globals.py:96]
<module> [default.py:call:764]
restricted [restricted.py:173]
run_controller_in [compileapp.py:426]
serve_controller [main.py:193]
wsgibase [main.py:478]
wsgiapp [gaehandler.py:71]
newfun [gaehandler.py:51]
run [handlers.py:92]
main [gaehandler.py:85]
ExecuteOrImportScript [dev_appserver.py:2187]
ExecuteCGI [dev_appserver.py:2289]
Dispatch [dev_appserver.py:2379]
Dispatch [dev_appserver.py:515]
_Dispatch [dev_appserver.py:3120]
_HandleRequest [dev_appserver.py:3177]
do_POST [dev_appserver.py:3069]
handle_one_request [BaseHTTPServer.py:310]
handle [BaseHTTPServer.py:316]
__init__ [SocketServer.py:522]
__init__ [dev_appserver.py:3057]
finish_request [SocketServer.py:254]
process_request [SocketServer.py:241]
handle_request [SocketServer.py:222]
serve_forever [SocketServer.py:201]
main [dev_appserver_main.py:402]
<module> [dev_appserver_main.py:417]
run_file [dev_appserver.py:63]
<module> [dev_appserver.py:67]
run [pydevd.py:780]
<module> [pydevd.py:953]

#from a function in default.py
(id, name, quota, users, usage) = team.update(auth.user.id, id, name)
# Line68

# from subscription.py.
def update(self, ownerId, teamId, name):
q = (self.db.team.owner_user_id == ownerId) \
& (self.db.team.id == teamId)
rows = self.db(q).select(self.db.team.ALL)

if rows:
rows[0].update_record(#name=name, # note I've commented
out this parameter to reproduce behavior
credit_quota=quota,
mDate=now) # *** Line 65 ***

mdipierro

unread,
Feb 3, 2010, 12:06:59 PM2/3/10
to web2py-users
Can you show us the model and attributes of db.team.
I suspect db.team.mDate is missing a writable=False, readable=False
which you need since it is a computed field.

Carl

unread,
Feb 3, 2010, 1:22:25 PM2/3/10
to web...@googlegroups.com
db.define_table('team',
Field('name', 'string', length=128, notnull=True,
required=True),
Field('name_lower', compute=lambda r:r['name'].lower()),
Field('owner_user_id', db.auth_user, required=True,
requires=IS_IN_DB(db,db.auth_user.id,'%(id)s')),
Field('credit_quota', 'integer', notnull=True, required=True),
Field('live', 'boolean', notnull=True,
required='True', default='True'),
Field('cDate', 'datetime', required=True),
Field('mDate', 'datetime', required=True))

Did you mean to refer to mDate rather than name (because it is
name_lower that is 'compute') ?

> --
> You received this message because you are subscribed to the Google Groups "web2py-users" group.
> To post to this group, send email to web...@googlegroups.com.
> To unsubscribe from this group, send email to web2py+un...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/web2py?hl=en.
>
>

mdipierro

unread,
Feb 3, 2010, 3:44:29 PM2/3/10
to web2py-users
Now the see this I understand the problem better. In this line:

Field('mDate', 'datetime', required=True)

required=True is not the same as requires=IS_NOT_EMPTY() and it is not
the same as notnull=True.

required=True means you cannot do insert without providing a value for
this field and that is exactly what you tell me the problem is.

On Feb 3, 12:22 pm, Carl <carl.ro...@gmail.com> wrote:
> db.define_table('team',
>                 Field('name', 'string', length=128, notnull=True,
> required=True),
>                 Field('name_lower', compute=lambda r:r['name'].lower()),
>                 Field('owner_user_id', db.auth_user, required=True,
> requires=IS_IN_DB(db,db.auth_user.id,'%(id)s')),
>                 Field('credit_quota', 'integer', notnull=True, required=True),
>                 Field('live', 'boolean', notnull=True,
> required='True', default='True'),
>                 Field('cDate', 'datetime', required=True),
>                 Field('mDate', 'datetime', required=True))
>
> Did you mean to refer to mDate rather than name (because it is
> name_lower that is 'compute') ?
>

Carl

unread,
Feb 3, 2010, 6:57:26 PM2/3/10
to web2py-users
I've traced right now to the exception and I get KeyError: 'name'

This is referring to the definition in db.py of the compute function


compute=lambda r:r['name'].lower()),

I've removed both notnull=True & required=True from:


Field('name', 'string', length=128, notnull=True, required=True),

but I still get the exception thrown.
I then remove all notnull and required and tested again... same
exception thrown.

however, as I said, if I include a name parameter in update_record all
is well. I think this provides a value for the compute formula to use.
I added this compute version recently and I think this is what's
tripping gae.

mdipierro

unread,
Feb 3, 2010, 8:16:20 PM2/3/10
to web2py-users
required is not really required for anything.

For debugging try:

Field('name_lower', compute=lambda
r:r['name'].lower(),readable=False,writable=False)

Perhaps you do not display the field name in the form?

Carl

unread,
Feb 3, 2010, 8:45:26 PM2/3/10
to web2py-users
ah... you are right; I don't get this information from a web2py form.

I added in readable and writable but still get the exception:
KeyError: 'name'

mdipierro

unread,
Feb 3, 2010, 10:15:58 PM2/3/10
to web2py-users
I needs to see more of the app to understand the workflow. This will
get rid of the problem:

Field('name_lower', compute=lambda
r:r.get('name','unknwon').lower(),readable=False,writable=False)

But somehow compute is being called without a prefilled record in your
app.

Reply all
Reply to author
Forward
0 new messages