[web2py] Re: Customizing Fields the lazy way

2018-04-16 Thread Anthony
Looks good. A few suggestions:

   - There is no benefit to using a class with a single static method here 
   -- just extract the new() method and make it a standalone function (maybe 
   call it field_factory).
   - If you rename kwargs in the new() function to something else (e.g., 
   fargs), then there is no need to make a copy of it -- just refer to it 
   directly in the inner function. So, you can drop the first line of both 
   new() and inner().
   - The .get() method already returns None if the key does not exist, so 
   no need to add False or None as the second argument.

Anthony

On Monday, April 16, 2018 at 12:37:18 AM UTC-4, Joe Barnhart wrote:
>
> Actually, I borrowed Anthony's excellent idea and made a "factory" class 
> for my field definitions.
>
> First I defined a factory class:
>
> class Field_Factory(object):
> from gluon import Field
> @staticmethod
> def new(**kwargs):
> default = dict(**kwargs)
> def inner(name, **kwargs):
> args = dict(default)
> args.update(**kwargs)
> if args.pop('hidden',False):
> args.update(dict(readable=False,writable=False))
> req = args.get('requires', None)
> if req and (args.get('represent',None)=='formatter'):
> args['represent'] = req.formatter
> if args.pop('optional',False) and req:
> args['requires'] = IS_EMPTY_OR(req)
> rend = args.pop('render',None)
> rtn = Field(name, **args)
> if rend:
> rtn.render = rend
> return rtn
> return inner
>
> factory = Field_Factory()
>
> Then I used it to create a bunch of field generators:
>
> phone_field = factory.new(
> type='string', length=20,
> requires=IS_PHONE(), optional=True,
> widget=lambda fld,val: SQLFORM.widgets.string.widget(
> fld, val, _type='tel', _class='form-control')
> )
>
> email_field = factory.new(
> type='string', length=50,
> requires=IS_EMAIL(), optional=True,
> widget=lambda fld,val: SQLFORM.widgets.string.widget(
> fld, val, _type='email', _class='form-control')
> )
>
> date_field = factory.new(
> type='date',
> requires=IS_DATE(format='%m-%d-%Y'), optional=True,
> represent=lambda v,r: v.strftime('%m-%d-%Y'),
> widget=lambda fld,val:SQLFORM.widgets.date.widget(
> fld, val, _class="date form-control")
> )
>
> datetime_field = factory.new(
> type='datetime',
> requires=IS_DATETIME(format='%m-%d-%Y %I:%M:%S %p'), optional=True,
> represent=lambda v,r: v.strftime('%m-%d-%Y %I:%M:%S %p'),
> widget=lambda fld,val: SQLFORM.widgets.datetime.widget(
> fld, val, _class="datetime form-control")
> )
>
> zipcode_field = factory.new(
> type='string', length=10,
> requires=IS_ZIPCODE(),
> widget=lambda fld,val: SQLFORM.widgets.string.widget(
> fld, val, _type="zip", _class='zipcode form-control')
> )
>
> Finally, when I use the field generators in any table definitions, I can 
> further customize them and the changes are passed through.  
>
> define_table('joes_table',
>. . .
>date_field("birth", label=T("Birth date")),
>phone_field('homephone', label=T("Home phone")),
>phone_field('workphone', label=T("Work phone")),
>phone_field('cellphone', label=T("Cell phone")),
>. . .
>
>
>
> It all works really well and gives me the single point of control I want. 
>  It requires no changes in web2py and works with current, past, and future 
> versions.  And the lazy programmer in me marvels at all the code I don't 
> have to type.
>
> -- Joe
>
> On Thursday, March 23, 2017 at 12:54:58 PM UTC-7, Joe Barnhart wrote:
>>
>> Here is a bit of syntactic sugar I use for creating fields with less 
>> typing.  And better consistency, of course -- there always has to be a good 
>> reason for my lazy keyboard-saving shortcuts!
>>
>> I have a number of fields which are for specific data types, such as 
>> phone numbers.  I gather the "common" parts of the Field definition into a 
>> dictionary:
>>
>> phone_fld = {'requires':IS_EMPTY_OR(IS_PHONE()),
>>  'widget':lambda fld,val: SQLFORM.widgets.string.widget(fld,
>> val,_type='tel',_class='form-control')}
>>
>> When defining the field in a table, I invoke the dictionary at the end of 
>> the Field definition:
>>
>> Field("homephone","string",length=20,label=T("Home phone"),**phone_fld),
>> Field("workphone","string",length=20,label=T("Work phone"),**phone_fld),
>> Field("cellphone","string",length=20,label=T("Cell phone"),**phone_fld),
>>
>> Now the field is created exactly as I want.  I keep a list of these 
>> "helpers" in a module which I can call out when creating tables.  It really 
>> saves the typing and allow me to control how my fields are rendered on one 
>> place instead of scattered among all the tables.
>>
>> -- Joe
>>
>>

-- 
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- 

Re: [web2py] Re: Customizing Fields the lazy way

2018-04-16 Thread Richard Vézina
Thanks Joe,

I will have a better read... I had fix my issue, my customization of the
plugin introduce a couple of problem... I ends up refactoring the and only
load data when all the controlled field has to be updated "once". It fix
80% of the loading time issue the rest of the issue is user related because
they don't actualize record status.

The workaround above wasn't really necessary.

Richard

On Mon, Apr 16, 2018 at 12:37 AM, Joe Barnhart 
wrote:

> Actually, I borrowed Anthony's excellent idea and made a "factory" class
> for my field definitions.
>
> First I defined a factory class:
>
> class Field_Factory(object):
> from gluon import Field
> @staticmethod
> def new(**kwargs):
> default = dict(**kwargs)
> def inner(name, **kwargs):
> args = dict(default)
> args.update(**kwargs)
> if args.pop('hidden',False):
> args.update(dict(readable=False,writable=False))
> req = args.get('requires', None)
> if req and (args.get('represent',None)=='formatter'):
> args['represent'] = req.formatter
> if args.pop('optional',False) and req:
> args['requires'] = IS_EMPTY_OR(req)
> rend = args.pop('render',None)
> rtn = Field(name, **args)
> if rend:
> rtn.render = rend
> return rtn
> return inner
>
> factory = Field_Factory()
>
> Then I used it to create a bunch of field generators:
>
> phone_field = factory.new(
> type='string', length=20,
> requires=IS_PHONE(), optional=True,
> widget=lambda fld,val: SQLFORM.widgets.string.widget(
> fld, val, _type='tel', _class='form-control')
> )
>
> email_field = factory.new(
> type='string', length=50,
> requires=IS_EMAIL(), optional=True,
> widget=lambda fld,val: SQLFORM.widgets.string.widget(
> fld, val, _type='email', _class='form-control')
> )
>
> date_field = factory.new(
> type='date',
> requires=IS_DATE(format='%m-%d-%Y'), optional=True,
> represent=lambda v,r: v.strftime('%m-%d-%Y'),
> widget=lambda fld,val:SQLFORM.widgets.date.widget(
> fld, val, _class="date form-control")
> )
>
> datetime_field = factory.new(
> type='datetime',
> requires=IS_DATETIME(format='%m-%d-%Y %I:%M:%S %p'), optional=True,
> represent=lambda v,r: v.strftime('%m-%d-%Y %I:%M:%S %p'),
> widget=lambda fld,val: SQLFORM.widgets.datetime.widget(
> fld, val, _class="datetime form-control")
> )
>
> zipcode_field = factory.new(
> type='string', length=10,
> requires=IS_ZIPCODE(),
> widget=lambda fld,val: SQLFORM.widgets.string.widget(
> fld, val, _type="zip", _class='zipcode form-control')
> )
>
> Finally, when I use the field generators in any table definitions, I can
> further customize them and the changes are passed through.
>
> define_table('joes_table',
> . . .
> date_field("birth", label=T("Birth date")),
> . . .
>
>
> It all works really well and gives me the single point of control I want.
> It requires no changes in web2py and works with current, past, and future
> versions.  And the lazy programmer in me marvels at all the code I don't
> have to type.
>
> -- Joe
>
> On Thursday, March 23, 2017 at 12:54:58 PM UTC-7, Joe Barnhart wrote:
>>
>> Here is a bit of syntactic sugar I use for creating fields with less
>> typing.  And better consistency, of course -- there always has to be a good
>> reason for my lazy keyboard-saving shortcuts!
>>
>> I have a number of fields which are for specific data types, such as
>> phone numbers.  I gather the "common" parts of the Field definition into a
>> dictionary:
>>
>> phone_fld = {'requires':IS_EMPTY_OR(IS_PHONE()),
>>  'widget':lambda fld,val: SQLFORM.widgets.string.widget(fld,
>> val,_type='tel',_class='form-control')}
>>
>> When defining the field in a table, I invoke the dictionary at the end of
>> the Field definition:
>>
>> Field("homephone","string",length=20,label=T("Home phone"),**phone_fld),
>> Field("workphone","string",length=20,label=T("Work phone"),**phone_fld),
>> Field("cellphone","string",length=20,label=T("Cell phone"),**phone_fld),
>>
>> Now the field is created exactly as I want.  I keep a list of these
>> "helpers" in a module which I can call out when creating tables.  It really
>> saves the typing and allow me to control how my fields are rendered on one
>> place instead of scattered among all the tables.
>>
>> -- Joe
>>
>> --
> 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, 

[web2py] Re: Customizing Fields the lazy way

2018-04-15 Thread Joe Barnhart
Actually, I borrowed Anthony's excellent idea and made a "factory" class 
for my field definitions.

First I defined a factory class:

class Field_Factory(object):
from gluon import Field
@staticmethod
def new(**kwargs):
default = dict(**kwargs)
def inner(name, **kwargs):
args = dict(default)
args.update(**kwargs)
if args.pop('hidden',False):
args.update(dict(readable=False,writable=False))
req = args.get('requires', None)
if req and (args.get('represent',None)=='formatter'):
args['represent'] = req.formatter
if args.pop('optional',False) and req:
args['requires'] = IS_EMPTY_OR(req)
rend = args.pop('render',None)
rtn = Field(name, **args)
if rend:
rtn.render = rend
return rtn
return inner

factory = Field_Factory()

Then I used it to create a bunch of field generators:

phone_field = factory.new(
type='string', length=20,
requires=IS_PHONE(), optional=True,
widget=lambda fld,val: SQLFORM.widgets.string.widget(
fld, val, _type='tel', _class='form-control')
)

email_field = factory.new(
type='string', length=50,
requires=IS_EMAIL(), optional=True,
widget=lambda fld,val: SQLFORM.widgets.string.widget(
fld, val, _type='email', _class='form-control')
)

date_field = factory.new(
type='date',
requires=IS_DATE(format='%m-%d-%Y'), optional=True,
represent=lambda v,r: v.strftime('%m-%d-%Y'),
widget=lambda fld,val:SQLFORM.widgets.date.widget(
fld, val, _class="date form-control")
)

datetime_field = factory.new(
type='datetime',
requires=IS_DATETIME(format='%m-%d-%Y %I:%M:%S %p'), optional=True,
represent=lambda v,r: v.strftime('%m-%d-%Y %I:%M:%S %p'),
widget=lambda fld,val: SQLFORM.widgets.datetime.widget(
fld, val, _class="datetime form-control")
)

zipcode_field = factory.new(
type='string', length=10,
requires=IS_ZIPCODE(),
widget=lambda fld,val: SQLFORM.widgets.string.widget(
fld, val, _type="zip", _class='zipcode form-control')
)

Finally, when I use the field generators in any table definitions, I can 
further customize them and the changes are passed through.  

define_table('joes_table',
. . .
date_field("birth", label=T("Birth date")),
. . .


It all works really well and gives me the single point of control I want. 
 It requires no changes in web2py and works with current, past, and future 
versions.  And the lazy programmer in me marvels at all the code I don't 
have to type.

-- Joe

On Thursday, March 23, 2017 at 12:54:58 PM UTC-7, Joe Barnhart wrote:
>
> Here is a bit of syntactic sugar I use for creating fields with less 
> typing.  And better consistency, of course -- there always has to be a good 
> reason for my lazy keyboard-saving shortcuts!
>
> I have a number of fields which are for specific data types, such as phone 
> numbers.  I gather the "common" parts of the Field definition into a 
> dictionary:
>
> phone_fld = {'requires':IS_EMPTY_OR(IS_PHONE()),
>  'widget':lambda fld,val: SQLFORM.widgets.string.widget(fld,
> val,_type='tel',_class='form-control')}
>
> When defining the field in a table, I invoke the dictionary at the end of 
> the Field definition:
>
> Field("homephone","string",length=20,label=T("Home phone"),**phone_fld),
> Field("workphone","string",length=20,label=T("Work phone"),**phone_fld),
> Field("cellphone","string",length=20,label=T("Cell phone"),**phone_fld),
>
> Now the field is created exactly as I want.  I keep a list of these 
> "helpers" in a module which I can call out when creating tables.  It really 
> saves the typing and allow me to control how my fields are rendered on one 
> place instead of scattered among all the tables.
>
> -- Joe
>
>

-- 
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.


Re: [web2py] Re: Customizing Fields the lazy way

2018-03-15 Thread Richard Vézina
I found a pretty unclean workaround...

You have to set the widget like this :

db.tablename.REFERENCEDTABLEOFCHILDFIELD.widget = \
lazy_options_widget(on_key='no_table_PARENTFIELDNAME__selected',
off_key='PARENTFIELDNAME__unselected',
where=lambda PARENTFIELDNAME:
(some where clause),
trigger=record_row.get('PARENTFIELDNAME', None),
orderby=db.REFERENCEDTABLEOFCHILDFIELD.id,
suggest_widget=False,
widget_chained=True,
row=record_row,

field_requires=db.tablename.REFERENCEDTABLEOFCHILDFIELD.requires
# We pass the original field requires that we want to be execute in context
to limit as much as possible the number of records that will be pulled out
the database and only when the parent field will be updated...
#user_signature=True,
# If you want to process ajax requests at the
time of the object construction
# (not at the form rendered), specify your
target field in the following:
)
db.tablename.REFERENCEDTABLEOFCHILDFIELD.requires = IS_IN_SET([1, 2,
3])  # Here redefine the child field or lazy option controlled field with
dummy not computer intensive requires that will be never displayed


NOTE: I have a customized version of lazy_option_widget (NOT THIS ONE :
https://github.com/scubism/sqlabs/blob/master/modules/plugin_lazy_options_widget.py)
that support reference field... So it might not make more sens without the
code so here it is...

# -*- coding: utf-8 -*-
# This plugins is licensed under the MIT license:
http://www.opensource.org/licenses/mit-license.php
# Authors: Kenji Hosoda 
# Support for reference field : Richard Vézina

from gluon import *


class lazy_options_widget(SQLFORM.widgets.options):

def __init__(self,
 on_key,
 off_key,
 where,
 trigger=None,  # Rename this attribute
 suggest_widget=True,  # In case you don't want to use
plugin_suggest_widget, set suggest_widget to
   # False. In this case, this piece of
js with be including :
   #
$("select[name=]").change(function() {
   # var val =
$(this).children(":selected").attr("value");
   #
 $(this).trigger($(this).attr("id") + "__selected", [val]);
   # });
   # Where 
will be replaced with the field name of the
   # conditional field name.
 widget_chained=False,  # In case the widget field is also
a conditional field for another widget field
# you need to trigger event like
"WIDGET_FIELD_NAME__selected" when the widget
# field option is finally selected
 widget_trigger_event_js=None,  # If you need to trigger
something when the widget field option is
# finally selected you can
pass a piece of js here that will be injected
# into the form when the
conditional field trigger event "__selected"
 default='---',
 keyword='_lazy_options_%(fieldname)s',
 orderby=None,
 user_signature=False,
 hmac_key=None,
 row=None,  # In order to set values and filtered drop down
appropriately based on values of
# conditional and widget field when the form is
populated. Since you can't get row like this
# Field(..., widget=lambda field, value, row:
...
# When form is populated (update form) you need
to define a row object base on the id of
# the record like this :
# row = db(db.table.id = request.vars.id
).select(db.table.ALL).first()
# and pass it to lazy_option_widget...
 field_requires=None,  # Better to set the field requires
here to get it evaluated in a lazy manner
 ):
self.on_key, self.off_key, self.where = (
on_key, off_key, where
)
self.field_requires = field_requires
self.trigger, self.default, self.keyword, self.orderby = (
trigger, default, keyword, orderby,
)
self.user_signature, self.hmac_key = user_signature, hmac_key

self.row = row

self.suggest_widget, self.widget_trigger_event_js,
self.widget_chained = (suggest_widget,

  widget_trigger_event_js,

   

Re: [web2py] Re: Customizing Fields the lazy way

2018-03-15 Thread Richard Vézina
I wonder if we could we also make field lazy that way in context of custom
form...

I find some issue with some of my custom form where I use Field() to define
my field that will be use... This form is also dynamic, I manipulate field
visibility and lazy_option_widget() to make some field depend of other
field... The things is with data build up...
requires=IS_EMPTY_OR(IS_IN_DB(_set_, 'table.id', ...)), is loading at first
(on form load) all the records almost everything as I can't specify the id
which will be selected in the parent field the one controlling the
lazy_option controlled field (hope I am understandable)... Multiply this by
3-4 time for each lazy_option controlled field and you ends up pulling
multiple time the same records...

I would be interred in making the IS_IN_DB() triggered select occuring only
when options needed to be displayed... I guess this is a flaw in the way
lazy_option_widget() is implemented in the first place though...

Richard

On Sun, Mar 26, 2017 at 6:34 AM, Joe Barnhart 
wrote:

> That's kinda clever.  I may think of that!
>
> -- Joe
>
>
> On Thursday, March 23, 2017 at 4:19:05 PM UTC-7, Anthony wrote:
>>
>> Note, you might as well also add 'type': 'string' to your dictionary, and
>> maybe 'length': 20. You can also give yourself some flexibility by creating
>> a function:
>>
>> def phone_field(name, **kwargs):
>> defaults = {'type': 'string',
>> 'length': 20,
>> 'requires': IS_EMPTY_OR(IS_PHONE()),
>> 'widget': lambda fld,val: SQLFORM.widgets.string.widget(
>> fld, val, _type='tel', _class='form-control')}
>> defaults.update(**kwargs)
>> return Field(name, **defaults)
>>
>> 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.
>

-- 
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.


[web2py] Re: Customizing Fields the lazy way

2017-03-26 Thread Joe Barnhart
That's kinda clever.  I may think of that!

-- Joe


On Thursday, March 23, 2017 at 4:19:05 PM UTC-7, Anthony wrote:
>
> Note, you might as well also add 'type': 'string' to your dictionary, and 
> maybe 'length': 20. You can also give yourself some flexibility by creating 
> a function:
>
> def phone_field(name, **kwargs):
> defaults = {'type': 'string',
> 'length': 20,
> 'requires': IS_EMPTY_OR(IS_PHONE()),
> 'widget': lambda fld,val: SQLFORM.widgets.string.widget(
> fld, val, _type='tel', _class='form-control')}
> defaults.update(**kwargs)
> return Field(name, **defaults)
>
> 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.


[web2py] Re: Customizing Fields the lazy way

2017-03-23 Thread Anthony
Note, you might as well also add 'type': 'string' to your dictionary, and 
maybe 'length': 20. You can also give yourself some flexibility by creating 
a function:

def phone_field(name, **kwargs):
defaults = {'type': 'string',
'length': 20,
'requires': IS_EMPTY_OR(IS_PHONE()),
'widget': lambda fld,val: SQLFORM.widgets.string.widget(
fld, val, _type='tel', _class='form-control')}
defaults.update(**kwargs)
return Field(name, **defaults)

Anthony

On Thursday, March 23, 2017 at 3:54:58 PM UTC-4, Joe Barnhart wrote:
>
> Here is a bit of syntactic sugar I use for creating fields with less 
> typing.  And better consistency, of course -- there always has to be a good 
> reason for my lazy keyboard-saving shortcuts!
>
> I have a number of fields which are for specific data types, such as phone 
> numbers.  I gather the "common" parts of the Field definition into a 
> dictionary:
>
> phone_fld = {'requires':IS_EMPTY_OR(IS_PHONE()),
>  'widget':lambda fld,val: SQLFORM.widgets.string.widget(fld,
> val,_type='tel',_class='form-control')}
>
> When defining the field in a table, I invoke the dictionary at the end of 
> the Field definition:
>
> Field("homephone","string",length=20,label=T("Home phone"),**phone_fld),
> Field("workphone","string",length=20,label=T("Work phone"),**phone_fld),
> Field("cellphone","string",length=20,label=T("Cell phone"),**phone_fld),
>
> Now the field is created exactly as I want.  I keep a list of these 
> "helpers" in a module which I can call out when creating tables.  It really 
> saves the typing and allow me to control how my fields are rendered on one 
> place instead of scattered among all the tables.
>
> -- Joe
>
>

-- 
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.