save the original value of one field in another field

201 views
Skip to first unread message

ahz...@gmail.com

unread,
Jul 10, 2016, 4:38:33 PM7/10/16
to web2py-users
In my application a user enters a boolean value, and later the user can modify the value. I want to save the original value in another field, and the user shouldn't be able to see or alter the original value.

Based on the stackoverflow conversation I tried a simple table with two  methods
db.define_table('mytable',
   
Field('start_number', 'integer', requires=IS_NOT_EMPTY()),
   
Field('n1', 'integer', default=request.post_vars.start_number),
   
Field('n2', 'integer', compute=lambda r: r.start_number)
   
)



Then I used the database administration to insert a value of 5, but n1 had a value of zero (instead of 5).

While n2 started with the value of 5, whenever I modified start_number, it also modified n2.

By the way, I wish I had web2py in 2003 when I started a bigger web application.

Michael Beller

unread,
Jul 10, 2016, 10:09:55 PM7/10/16
to web2py-users
For n2, you could try only updating if n2 was not empty.  This is not tested but something like ...

Field('n2', 'integer', compute=lambda r: r.start_number if not r.n2 else None)

ahz...@gmail.com

unread,
Jul 10, 2016, 11:16:01 PM7/10/16
to web2py-users
Michael,

I tried this new model where n3 is your suggestion and n4 is derived from your suggestion.

db.define_table('mytable',
   
Field('start_number', 'integer', requires=IS_NOT_EMPTY()),
   
Field('n1', 'integer', default=request.post_vars.start_number),

   
Field('n2', 'integer', compute=lambda r: r.start_number),
   
Field('n3', 'integer', compute=lambda r: r.start_number if not r.n3 else None),
   
Field('n4', 'integer', compute=lambda r: r.start_number if r.n4 is None else r.r4),
   
)

However, after insert n3 and n4 are both None.

(n1, n2, n3, and n4 are all attempts to meet the same need. I included them all in one model for comparison.)


Andrew

Anthony

unread,
Jul 10, 2016, 11:25:20 PM7/10/16
to web2py-users
On Sunday, July 10, 2016 at 10:09:55 PM UTC-4, Michael Beller wrote:
For n2, you could try only updating if n2 was not empty.  This is not tested but something like ...

Field('n2', 'integer', compute=lambda r: r.start_number if not r.n2 else None)

That won't work because (a) the current value of n2 will not be included in r, and (b) even if it were, you would not want to set the value of n2 to None.

Anthony

Anthony

unread,
Jul 10, 2016, 11:43:22 PM7/10/16
to web2py-users
On Sunday, July 10, 2016 at 4:38:33 PM UTC-4, ahz...@gmail.com wrote:
In my application a user enters a boolean value, and later the user can modify the value. I want to save the original value in another field, and the user shouldn't be able to see or alter the original value.

Based on the stackoverflow conversation I tried a simple table with two  methods
db.define_table('mytable',
   
Field('start_number', 'integer', requires=IS_NOT_EMPTY()),
   
Field('n1', 'integer', default=request.post_vars.start_number),

n1 won't work because it is writable and therefore appears in the form, which means even if you leave it blank, an empty string is submitted as its value, which SQLFORM converts to a 0 (the default value is inserted only if no value is submitted).

Here are two options:

db.define_table('mytable',
   
Field('modifiable_number', 'integer', requires=IS_NOT_EMPTY()),
   
Field('original1', 'integer', readable=False, writable=False,
         
default=request.post_vars.modifiable_number),
   
Field('original2', 'integer'
, readable=False, writable=False,
          compute
=lambda r: r.modifiable_number)
)

db
.mytable._before_update = [lambda t, f: setattr(db.mytable.original2, 'compute', None)]

Because original1 is not writable, it will not appear in the form, which means no value will be submitted for it and therefore its default value will be inserted. Note, however, that this will not work in appadmin, which ignores the "writable" attribute and will therefore include original1 in the insert form.

original2 will use the computed value only on the initial insert. The _before_update callback removes the "compute" attribute before any updates, so no new value will be computed on updates. Note, if you need to do an insert after an update during the same HTTP request (which is probably not a common scenario), you would also need to add an _after_update callback to restore the "compute" attribute after the update.

Anthony

Anthony

unread,
Jul 10, 2016, 11:53:30 PM7/10/16
to web...@googlegroups.com
Here's a potentially better option that will work even in appadmin and doesn't require an extra callback if you need to do an insert followed by an update in the same request:

db.define_table('mytable',
   
Field('modifiable_number', 'integer', requires=IS_NOT_EMPTY()),

   
Field('original', 'integer', readable=False, writable=False
))

db
.mytable._before_insert = [lambda fields: fields.update(original=fields.get('modifiable_number'))]

With the above solution, there is no default or compute attribute. Instead, before an insert (but not before an update), the value of the "original" field is set to match the value of the "modifiable_number" field.

Anthony

Andrew Ziem

unread,
Jul 11, 2016, 10:37:52 AM7/11/16
to web...@googlegroups.com
Anthony,

The _before_insert works perfectly. Thank you.


Andrew
> --
> 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 a topic in the
> Google Groups "web2py-users" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/web2py/vMe41spAnCY/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> web2py+un...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages