web2py Field Exegesis

web2py Field Exegesis

Joe Dorocak aka Joe Codeswell has written working Python code examples exploring “fully qualified” web2py Field constructors.

I wrote this to turn the web2py book chapter on the Field constructor into working, “fully qualified” examples, so I could understand the meaning and explore the features. There are 2 “fully qualified” examples in mytable for now:

  • fulldefaultstrfield – is my cut at fully qualifying the default settings for the Field constructor named parameters.
  • fullplay1strfield – is my 1st cut at playing around with the values of the named parameters in the Field constructor.

The results can be seen by implementing this locally and navigating to:

Content

  • In applications/fields/controllers/default.py
  • In applications/fields/models/db.py

In applications/fields/controllers/default.py

# -*- coding: utf-8 -*-
# In applications/fields/controllers/default.py

def gridmytable():
    grid = SQLFORM.grid(db.mytable)
    return locals()

In applications/fields/models/db.py

# -*- coding: utf-8 -*-
# In applications/fields/models/db.py

# web2py Field Exegesis
# Joe Dorocak aka Joe Codeswell has written working Python code examples exploring "fully qualified" web2py Field constructors. 
# I wrote this to turn the web2py book chapter on the Field constructor into working, "fully qualified" examples, so i could understand the meaning and explore the features. There are 2 "fully qualified" examples in mytable for now.
#  - fulldefaultstrfield - is my cut at fullyqualifying the default settings for the Field constructor named parameters.
#  - fullplay1strfield   - is my 1st cut at playing around with the values of the named parameters in the Field constructor.
# The results can be seen by implementing this locally and navigating to
#   -  inserting new records at   http://127.0.0.1:8000/fields/appadmin/select/db 
#   -  seeing the table grid at   http://127.0.0.1:8000/fields/default/gridmytable


# BOILERPLATE
if not request.env.web2py_runtime_gae:
    db = DAL('sqlite://storage.sqlite',pool_size=1,check_reserved=['all'])
else:
    db = DAL('google:datastore')
    session.connect(request, response, db=db)

response.generic_patterns = ['*'] if request.is_local else []

from gluon.tools import Auth, Crud, Service, PluginManager, prettydate
auth = Auth(db)
crud, service, plugins = Crud(db), Service(), PluginManager()

## create all tables needed by auth if not custom tables
auth.define_tables(username=False, signature=False)
# END BOILERPLATE



# START HERE
db.define_table('mytable',

        Field('myfield','string'),

        # see http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#Field-constructor
        # a fully defined field example that will HOPEFULLY work
        # Not all of the parameters are relevant for every field type.
        Field(
         'fulldefaultstrfield',        # Field name positional arg
          type='string',               # Field type see field_types below

          # Sets the maximum length of a "string", "password" or "upload" field.
          #     See "2.6.1 - 2.6.4" in  http://www.web2py.com/init/default/changelog
          #         "MySQL users: The length of string fields changed from 255 to 512 bytes. 
          length=512,       

          default='',                  # Default value used to pre-populate forms, can instead be a [lambda] function 
          required=False,              # True => A val for field MUST be specified at record insertion.
          requires=IS_LENGTH(512),     # Is a validator or a list of validators. see book /forms-and-validators#Validators. see field_types below    # joeNote: bad_value == '<DEFAULT>'
          ondelete='CASCADE',          # Defines actions on record delete. CASCADE => delete all referring records
          notnull=False,               # True => fulldeffield can't be Null at record insertion.
          unique=False,                # True => must be unique in the table [not quite the same as IS_NOT_IN_DB]
          uploadfield=True,            # Applies only to fields of type "upload" [Even though True is default and works for type=='string']. See upload_field_type_notes below

          # Must be one of the available widget objects, including custom widgets. 
          # Each field type has a default widget. See widgetList below   
          # This is default for fulldeffield.type=='string'          
          widget=SQLFORM.widgets.string.widget, 

          label=None,                  # Is a string (or a helper or something that can be serialized to a string) that contains the label to be used for this field in auto-generated forms.
                                       #     JoeNote: There's a diff between label=None => default label & label='' => NO LABEL SHOWN!
          comment='',                  # Is a string (or a helper or something that can be serialized to a string) that contains a comment associated with this field, and will be displayed to the right of the input field in the autogenerated forms. 
                                       #      JoeNote: No diff between comment='' & comment=None
          # If a field is neither readable nor writable, it will not be displayed in create and update forms.
          writable=True,               # Declares whether a field is writable in forms.
          readable=True,               # Declares whether a field is readable in forms.

          update=None,                 # Contains the default value for this field when the record is updated.

          authorize=None,              # For "upload" fields only, can be used to require access control on the corresponding field. See Authentication and also Authorization http://web2py.com/books/default/chapter/29/09/access-control.
          autodelete=False,            # For "upload" fields only, determines if the corresponding uploaded file should be deleted when the record referencing the file is deleted. 

          represent=None,              # Can be None or can point to a function that takes a field value and returns an alternate representation for the field value. See representation_examples below.         
          compute=None,                # See compute_notes below.

          uploadfolder=None,           # See upload_field_type_notes below
          uploadseparate=None,         # See upload_field_type_notes below
          uploadfs=None                # See upload_field_type_notes below
        ), 

        # joe says do a diff on following & above to hilight what changed
        #    i think i changed: fieldname, length, requires, label, comment, represent
        # need to provide insert & rendering actions to see diffs in result

        # see http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#Field-constructor
        # a fully defined field example that will HOPEFULLY work
        # Not all of the parameters are relevant for every field type.
        Field(
         'fullplay1strfield',          # Field name positional arg
          type='string',               # Field type see field_types below

          # Sets the maximum length of a "string", "password" or "upload" field.
          #     See "2.6.1 - 2.6.4" in  http://www.web2py.com/init/default/changelog
          #         "MySQL users: The length of string fields changed from 255 to 512 bytes. 
          length=4096,       

          default='',                  # Default value used to pre-populate forms, can instead be a [lambda] function 
          required=False,              # True => A val for field MUST be specified at record insertion.
          requires=IS_LENGTH(4096),    # Is a validator or a list of validators. see book /forms-and-validators#Validators. see field_types below    # joeNote: bad_value == '<DEFAULT>'
          ondelete='CASCADE',          # Defines actions on record delete. CASCADE => delete all referring records
          notnull=False,               # True => fulldeffield can't be Null at record insertion.
          unique=False,                # True => must be unique in the table [not quite the same as IS_NOT_IN_DB]
          uploadfield=True,            # Applies only to fields of type "upload" [Even though True is default and works for type=='string']. See upload_field_type_notes below

          # Must be one of the available widget objects, including custom widgets. 
          # Each field type has a default widget. See widgetList below   
          # This is default for fulldeffield.type=='string'          
          widget=SQLFORM.widgets.string.widget, 

          label='lblPlay1strfield',    # Is a string (or a helper or something that can be serialized to a string) that contains the label to be used for this field in auto-generated forms.
                                       #     JoeNote: There's a diff between label=None => default label & label='' => NO LABEL SHOWN!
          comment='cmtPlay1strfield',  # Is a string (or a helper or something that can be serialized to a string) that contains a comment associated with this field, and will be displayed to the right of the input field in the autogenerated forms. 
                                       #      JoeNote: No diff between comment='' & comment=None
          # If a field is neither readable nor writable, it will not be displayed in create and update forms.
          writable=True,               # Declares whether a field is writable in forms.
          readable=True,               # Declares whether a field is readable in forms.

          update=None,                 # Contains the default value for this field when the record is updated.

          authorize=None,              # For "upload" fields only, can be used to require access control on the corresponding field. See Authentication and also Authorization http://web2py.com/books/default/chapter/29/09/access-control.
          autodelete=False,            # For "upload" fields only, determines if the corresponding uploaded file should be deleted when the record referencing the file is deleted. 

          # Can be None or can point to a function that takes a field value and returns an alternate representation for the field value. See representation_examples below.         
          # represent=lambda fullplay1strfield,row: fullplay1strfield.capitalize(),              
          #     result ticket: File "C:/web2py/applications/fields/models/db.py", line 194, in <lambda>
          #         represent=lambda fullplay1strfield,row: fullplay1strfield.capitalize(),
          #         AttributeError: 'NoneType' object has no attribute 'capitalize'
          #    it was None

          represent=lambda fullplay1strfield,row: fullplay1strfield.capitalize(),
          compute=None,                # See compute_notes below.

          uploadfolder=None,           # See upload_field_type_notes below
          uploadseparate=None,         # See upload_field_type_notes below
          uploadfs=None                # See upload_field_type_notes below
        ), 



    )



# see http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#Field-types
field_types = '''
field_type              default_field_validators
string                  IS_LENGTH(length) default length is 512
text                    IS_LENGTH(65536)
blob                    None
boolean                 None
integer                 IS_INT_IN_RANGE(-1e100, 1e100)
double                  IS_FLOAT_IN_RANGE(-1e100, 1e100)
decimal(n,m)            IS_DECIMAL_IN_RANGE(-1e100, 1e100)
date                    IS_DATE()
time                    IS_TIME()
datetime                IS_DATETIME()
password                None
upload                  None
reference <table>     IS_IN_DB(db,table.field,format)
list:string             None
list:integer            None
list:reference <table>    IS_IN_DB(db,table.field,format,multiple=True)
json                    IS_JSON()
bigint                  None
big-id                  None
big-reference           None
'''

upload_field_type_notes = '''
    uploadfield:
        applies only to fields of type "upload". A field of type "upload" stores the name of a file saved somewhere else, by default on the filesystem under the application "uploads/" folder. If uploadfield is set to True, then the file is stored in a blob field within the same table and the value of uploadfield is the name of the blob field. This will be discussed in more detail later in the context of SQLFORM.
    uploadfolder:
        defaults to the application's "uploads/" folder. If set to a different path, files will uploaded to a different folder. For example,
            Field(...,uploadfolder=os.path.join(request.folder,'static/temp'))
        will upload files to the "web2py/applications/myapp/static/temp" folder.
    uploadseparate:
        if set to True will upload files under different subfolders of the uploadfolder folder. This is optimized to avoid too many files under the same folder/subfolder. ATTENTION: You cannot change the value of uploadseparate from True to False without breaking links to existing uploads. web2py either uses the separate subfolders or it does not. Changing the behavior after files have been uploaded will prevent web2py from being able to retrieve those files. If this happens it is possible to move files and fix the problem but this is not described here.
    uploadfs:
        allows you specify a different file system where to upload files, including an Amazon S3 storage or a remote SFTP storage. This option requires PyFileSystem installed. uploadfs must point to PyFileSystem. uploadfs
'''

widgetList = [
# See http://web2py.com/books/default/chapter/29/07/forms-and-validators?search=widgets#Widgets
# Here is a list of available web2py widgets:
    SQLFORM.widgets.string.widget,         # default for corresonding type
    SQLFORM.widgets.text.widget,           # default for corresonding type
    SQLFORM.widgets.password.widget,       # default for corresonding type
    SQLFORM.widgets.integer.widget,        # default for corresonding type
    SQLFORM.widgets.double.widget,         # default for corresonding type
    SQLFORM.widgets.time.widget,           # default for corresonding type
    SQLFORM.widgets.date.widget,           # default for corresonding type
    SQLFORM.widgets.datetime.widget,       # default for corresonding type
    SQLFORM.widgets.upload.widget,         # default for corresonding type
    SQLFORM.widgets.boolean.widget,        # default for corresonding type

    # The next 2 widgets are used when a field's requires is IS_IN_SET or IS_IN_DB
    # The "options" widget is used with multiple=False (default behavior), when a field's requires is IS_IN_SET or IS_IN_DB.
    SQLFORM.widgets.options.widget,
    # The "multiple" widget is used with multiple=True, when a field's requires is IS_IN_SET or IS_IN_DB. 
    SQLFORM.widgets.multiple.widget,

    # The "radio" and "checkboxes" widgets are never used by default, but can be set manually. 
    SQLFORM.widgets.radio.widget,    
    SQLFORM.widgets.checkboxes.widget,

    # See http://web2py.com/books/default/chapter/29/07/forms-and-validators?search=widgets#Autocomplete-widget
    SQLFORM.widgets.autocomplete,
    ]

representation_examples = '''
db.mytable.name.represent = lambda name,row: name.capitalize()
db.mytable.other_id.represent = lambda id,row: row.myfield
db.mytable.some_uploadfield.represent = lambda value,row:     A('get it', _href=URL('download', args=value))

"blob" fields are also special. 
By default, binary data is encoded in base64 before being stored into the actual database field, and it is decoded when extracted. 
This has the negative effect of using 25% more storage space than necessary in blob fields, but has two advantages. 
On average it reduces the amount of data communicated between web2py and the database server, and it makes the communication independent of back-end-specific escaping conventions.
'''    

compute_notes = '''
from http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#Computed-fields
Computed fields

DAL fields may have a compute attribute. This must be a function (or lambda) that takes a Row object and returns a value for the field. When a new record is modified, including both insertions and updates, if a value for the field is not provided, web2py tries to compute from the other field values using the compute function. Here is an example:

>>> db.define_table('item',
        Field('unit_price','double'),
        Field('quantity','integer'),
        Field('total_price',
            compute=lambda r: r['unit_price']*r['quantity']))
>>> r = db.item.insert(unit_price=1.99, quantity=5)
>>> print r.total_price
9.95

Notice that the computed value is stored in the db and it is not computed on retrieval, as in the case of virtual fields, described later. Two typical applications of computed fields are:

    in wiki applications, to store the processed input wiki text as HTML, to avoid re-processing on every request
    for searching, to compute normalized values for a field, to be used for searching.

Computed fields are evaluated in the order in which they are defined in the table definition. A computed field can refer to previously defined computed fields (new after v 2.5.1)
Virtual fields

Virtual fields are also computed fields ...
    see: http://web2py.com/books/default/chapter/29/06/the-database-abstraction-layer#Virtual-fields
'''

grid_notes = '''

SQLFORM.grid signature
    http://web2py.com/books/default/chapter/29/07/forms-and-validators#SQLFORM-grid-signature

The complete signature for the grid is the following:

SQLFORM.grid(
    query,
    fields=None,
    field_id=None,
    left=None,
    headers={},
    orderby=None,
    groupby=None,
    searchable=True,
    sortable=True,
    paginate=20,
    deletable=True,
    editable=True,
    details=True,
    selectable=None,
    create=True,
    csv=True,
    links=None,
    links_in_grid=True,
    upload='<default>',
    args=[],
    user_signature=True,
    maxtextlengths={},
    maxtextlength=20,
    onvalidation=None,
    oncreate=None,
    onupdate=None,
    ondelete=None,
    sorter_icons=(XML('↑'), XML('↓')),
    ui = 'web2py',
    showbuttontext=True,
    _class="web2py_grid",
    formname='web2py_grid',
    search_widget='default',
    ignore_rw = False,
    formstyle = 'table3cols',
    exportclasses = None,
    formargs={},
    createargs={},
    editargs={},
    viewargs={},
    buttons_placement = 'right',
    links_placement = 'right'
    )

...
JoeNite: below => see SQLFORM
    http://web2py.com/books/default/chapter/29/07/forms-and-validators#SQLFORM
        http://web2py.com/books/default/chapter/29/07/forms-and-validators#SQLFORM-and-insert-update-delete
            google: SQLFORM for select
                https://groups.google.com/forum/#!topic/web2py/VKvw3Mn-mNQ


Because the edit/create form is an SQLFORM which extends FORM, these callbacks are essentially used in the same way as documented in the sections for FORM and SQLFORM.

Here is skeleton code:

def myonvalidation(form):
    print "In onvalidation callback"
    print form.vars
    form.errors= True  #this prevents the submission from completing

    #...or to add messages to specific elements on the form
    form.errors.first_name = "Do not name your child after prominent deities" 
    form.errors.last_name = "Last names must start with a letter"
    response.flash = "I don't like your submission" 

def myoncreate(form):
    print 'create!'
    print form.vars

def myonupdate(form):
    print 'update!'
    print form.vars

def myondelete(table, id):
    print 'delete!'
    print table, id

onupdate and oncreate are the same callbacks available to SQLFORM.process()    
'''    
Advertisements

One thought on “web2py Field Exegesis

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s