Making a field non-editable, but writable using SQLFORM

1,232 views
Skip to first unread message

Jay Shaffstall

unread,
Jun 16, 2011, 2:05:34 PM6/16/11
to web...@googlegroups.com
I have a situation where I need to adjust an SQLFORM field to be
non-editable. I can do that with .writable = False, but that seems to
also prevents database I/O for that field. What I'm trying to do is
set a default that cannot be changed.

Is there a way to set an SQLFORM field so that it appears as a label
on the form itself, but is still writable for the database?

For reference, I'm doing this with a field in the form returned by
auth.register, so I cannot insert code between the form creation and
the accepts call. I believe I'm restricted to working with the model
before calling auth.register, or by using custom forms.

Jay

Bruno Rocha

unread,
Jun 16, 2011, 2:18:53 PM6/16/11
to web...@googlegroups.com

You can change this on the fly, no need to do it only in models, it can be done in controllers.


### controllers/comecontroller.py

db.table.field.writable = False # change the field to writable false

form = SQLFORM(db.table) # build the form 

db.table.field.writable = True  #change it again

return dict(form=form)




--
Bruno Rocha

Bruno Rocha

unread,
Jun 16, 2011, 2:21:26 PM6/16/11
to web...@googlegroups.com

Sorry, I answered before read entire message,

if you want to chamhe it in form only, better to use the 'represent' attribute

db.table.field.represent = lambda f: "<label> %s </label>" % f


--
Bruno Rocha

On Thu, Jun 16, 2011 at 3:05 PM, Jay Shaffstall <jshaf...@gmail.com> wrote:

Jay Shaffstall

unread,
Jun 16, 2011, 2:57:59 PM6/16/11
to web...@googlegroups.com
That doesn't seem to affect the HTML form output at all for me. I've
also tried changing the widget to LABEL, but that results in the same
problem with the value not being transmitted back via the form.

What I'd like to be able to do is set the readonly attribute of the
input tag; but I don't know how to do that in this context, where I
cannot insert code between the creation on the SQLFORM and the accepts
call.

Jay

DenesL

unread,
Jun 16, 2011, 5:06:11 PM6/16/11
to web2py-users

Jay, you can do:

form.element('#tablename_fieldname')['_readonly']=True


On Jun 16, 2:57 pm, Jay Shaffstall <jshaffst...@gmail.com> wrote:
> That doesn't seem to affect the HTML form output at all for me.  I've
> also tried changing the widget to LABEL, but that results in the same
> problem with the value not being transmitted back via the form.
>
> What I'd like to be able to do is set the readonly attribute of the
> input tag; but I don't know how to do that in this context, where I
> cannot insert code between the creation on the SQLFORM and the accepts
> call.
>
> Jay
>
>
>
>
>
>
>
> On Thu, Jun 16, 2011 at 2:21 PM, Bruno Rocha <rochacbr...@gmail.com> wrote:
>
> > Sorry, I answered before read entire message,
> > if you want to chamhe it in form only, better to use the 'represent'
> > attribute
> > db.table.field.represent = lambda f: "<label> %s </label>" % f
>
> > --
> > Bruno Rocha
> > [ About me: http://zerp.ly/rochacbruno ]
>
> > On Thu, Jun 16, 2011 at 3:05 PM, Jay Shaffstall <jshaffst...@gmail.com>

Anthony

unread,
Jun 16, 2011, 5:11:29 PM6/16/11
to web...@googlegroups.com
On Thursday, June 16, 2011 2:05:34 PM UTC-4, JayShaffstall wrote:
I have a situation where I need to adjust an SQLFORM field to be
non-editable.  I can do that with .writable = False, but that seems to
also prevents database I/O for that field.  What I'm trying to do is
set a default that cannot be changed.
 
How are you setting the default? If you specify the 'default' argument for the Field object, it should enter that default even if you set writable=False (at least it does for me, though I haven't tested it specifically on the auth_user table). Can you show some of your code?
 

For reference, I'm doing this with a field in the form returned by
auth.register, so I cannot insert code between the form creation and
the accepts call.  I believe I'm restricted to working with the model
before calling auth.register, or by using custom forms.

 
Depending on what you need to do, I think you should be able to alter the auth form before it gets passed on to the view. In your user() function, do something like this:
 
def user():
    form=auth()  # This creates the appropriate auth form, depending on request.args.
    if request.args and request.args(0)=='register':
        # code to alter the registration form
    return dict(form=form)
 
 
Note, if you want to do something after registration form validation but before the form is accepted, you can also specify auth.settings.register_onvalidation (see http://web2py.com/book/default/chapter/08#Settings-and-Messages).
 
Anthony

Jay Shaffstall

unread,
Jun 16, 2011, 5:12:27 PM6/16/11
to web...@googlegroups.com
I'd been thinking I needed to do that between form creation and the
accepts call, but you're right, it works even after that point. I
make the call to auth.register, and then modify the readonly
attribute, and it works fine.

Thanks!
Jay

amit

unread,
Jul 17, 2012, 12:24:37 AM7/17/12
to web...@googlegroups.com
Old thread, but this would trigger a race condition in case of multiple concurrent users. 

Anthony

unread,
Jul 17, 2012, 12:46:15 AM7/17/12
to web...@googlegroups.com
Can you elaborate?

Amit Kumar

unread,
Jul 17, 2012, 4:47:29 AM7/17/12
to web...@googlegroups.com

I understand the proposed procedure is as follows:

1. change db table field to writable
2. make the form as needed
3. change back db table field to not writable

Suppose there are two concurrent users now, A and B, and they execute the above procedure.  
The concurrent scheduling is done by the server; one possible sequence is:

A 1, B 1, B 2, B 3, <problem occurs> A 2, A 3. 

At the point of <problem occurs>, the db field is not writable and so the form will not be correct. 

Can you elaborate?
--
 
 
 

Anthony

unread,
Jul 17, 2012, 5:29:51 AM7/17/12
to web...@googlegroups.com
I understand the proposed procedure is as follows:

1. change db table field to writable
2. make the form as needed
3. change back db table field to not writable

First, I don't think this is the proposal. The proposal was to manipulate the form object itself after the form is created, but before it is serialized in the view (i.e., set the HTML "readonly" attribute of the input widget).

Second, even something like the above wouldn't be a problem for concurrent users, as the above would all happen within a single request and therefore only apply to that one request. Setting a field to writable in one request does not affect it another request.

Anthony

amit

unread,
Jul 17, 2012, 6:00:00 AM7/17/12
to web...@googlegroups.com


On Tuesday, July 17, 2012 5:29:51 PM UTC+8, Anthony wrote:
I understand the proposed procedure is as follows:

1. change db table field to writable
2. make the form as needed
3. change back db table field to not writable

First, I don't think this is the proposal. The proposal was to manipulate the form object itself after the form is created, but before it is serialized in the view (i.e., set the HTML "readonly" attribute of the input widget).

Yes, this will work fine. 

Sorry, I was referring to 

db.table.field.writable = False # change the field to writable false
 
Second, even something like the above wouldn't be a problem for concurrent users, as the above would all happen within a single request and therefore only apply to that one request. Setting a field to writable in one request does not affect it another request.

I am not sure if I understand this for db.table.field.writable. The change is occurring within the shared DAL object. Is it not? 

Best Regards
-Amit
 

Anthony

unread,
Jul 17, 2012, 6:20:53 AM7/17/12
to
Sorry, I was referring to 

db.table.field.writable = False # change the field to writable false
 
Second, even something like the above wouldn't be a problem for concurrent users, as the above would all happen within a single request and therefore only apply to that one request. Setting a field to writable in one request does not affect it another request.

I am not sure if I understand this for db.table.field.writable. The change is occurring within the shared DAL object. Is it not?

No, the DAL object is not shared. Each request happens in a separate thread, and all the objects generated in the app code are specific to that request and thread. The database itself is shared and accessible from multiple requests, but the web2py objects defined in the app code are not. If the writable attribute of a field is set in one request, that does not affect its status in another request.

The cache and session are also persistent across requests, but if sessions are stored in files, the files are locked, so only one request can access a given session at a time (this is not the case if stored in the database).

Anthony

Amit Kumar

unread,
Jul 17, 2012, 6:18:45 AM7/17/12
to web...@googlegroups.com
On Tue, Jul 17, 2012 at 6:15 PM, Anthony <abas...@gmail.com> wrote:
Sorry, I was referring to 

db.table.field.writable = False # change the field to writable false
 
Second, even something like the above wouldn't be a problem for concurrent users, as the above would all happen within a single request and therefore only apply to that one request. Setting a field to writable in one request does not affect it another request.

I am not sure if I understand this for db.table.field.writable. The change is occurring within the shared DAL object. Is it not?

No, the DAL object is not shared. Each request happens in a new thread, and all the objects generated in the app code are specific to that request and thread. The database itself is shared and accessible from multiple requests, but the web2py objects defined in the app code are not. If the writable attribute of a field is set in one request, that does not affect its status in another request.

Got it! Thanks for clarifying. 
 

Massimo Di Pierro

unread,
Jul 17, 2012, 11:37:55 AM7/17/12
to web...@googlegroups.com
Doesn't 

db.table.field.writable = False
db.table.field.default = 'whatever'

do what you want?

vinic...@gmail.com

unread,
Jul 17, 2012, 11:40:52 AM7/17/12
to web...@googlegroups.com
Maybe Massimo's ideia can work for you.

But don't be afraid to count on custom forms. They give us much more power.
> --
>
>
>

Reply all
Reply to author
Forward
0 new messages