Hi guys,
Thanks for all the input and recommendations.
No problem about overwriting anything because all my extended methods start
with x_*.
Same approach I follow for all my table and field definitions, all starting
with x*, and this way I can use any name I want without any problems with
reserved words.
With respect to the "why", it's just for convenience of executing these
extended methods from the actual pertinent instance (using self.*).
Furthermore I believe that I finally solved my concurrency problems with the
following approach (if anyone is interested):
+ remember to use the following to track changes (at the beginning of your
model):
from gluon.custom_import import track_changes
track_changes()
+ access "current" in your model:
now = request.now
from gluon import current
# assign any object(s) to current to be shared/accessed via the extended
methods.
current.now = now
+ do the following immediately after you define the db in your model (in
order to access "current" via the "db" in the extended methods):
current.db = db
db.current = current
+ import the module to be created in your model:
from MODULE_EXTENSIONS import *
+ implement the following as a module (not model) in order to create all the
extensions (MODULE_EXTENSIONS.py).
=== === ===
from gluon import dal, sqlhtml
from gluon.storage import Storage
cls = Storage()
cls.db = DAL
cls.table = dal.Table
cls.field = dal.Field
cls.set = dal.Set
cls.rows = dal.Rows
cls.reference = dal.Reference
cls.row = dal.Row
cls.form = sqlhtml.SQLFORM
# in each of x_mymethods, accept args, vars, and do & return whatever is
necessary in the *inner* methods.
# you can have any number of extended methods per class, and you can extend
other system classes as well.
# access the environment-specific db (thread/concurrent safe, so far?) in
each case via the comments in each of the below classes.
# access the environment-specific "current" (thread/concurrent safe, so
far?) via (db).current.
# db ... self
class Xx_db(object):
def x_mymethod(self):
def _(self, *args, **kwargs):
# do anything here with self as the actual DAL.
return 'return any'
return _
# db ... self._db
class Xx_table(object):
def x_mymethod(self):
def _(self, *args, **kwargs):
# do anything here with self as the actual Table.
return 'return any'
return _
# db ... self.db
class Xx_field(object):
def x_mymethod(self):
def _(self, *args, **kwargs):
# do anything here with self as the actual Field.
return 'return any'
return _
# db ... self.db
class Xx_set(object):
def x_mymethod(self):
def _(self, *args, **kwargs):
# do anything here with self as the actual Set.
return 'return any'
return _
# db ... self.db
class Xx_rows(object):
def x_mymethod(self):
def _(self, *args, **kwargs):
# do anything here with self as the actual Rows.
return 'return any'
return _
# just redirect to the respective row.
class Xx_reference(object):
def x_self(self):
def _(self):
self._dummy_ # in order to force __allocate().
return self._record
return _
# redirect all necessary methods to the row object.
def x_mymethod(self):
def _(self, *args, **kwargs):
return self.x_self().x_mymethod(*args, **kwargs)
return _
# for Row, you can assign the following virutal field in your model
# in order to directly access the db:
# def db(self): return db
# db ... self.db
class Xx_row(object):
def x_mymethod(self):
def _(self, *args, **kwargs):
# do anything here with self as the actual Row.
return 'return any'
return _
# db ... self.table._db
class Xx_form(object):
def x_mymethod(self):
def _(self, *args, **kwargs):
# do anything here with self as the actual SQLFORM.
return 'return any'
return _
# do all the magic to extend the above classes with the respective methods.
def doXx():
prefix = 'Xx_'
xclasses = [ v for (k, v) in globals().items() if k.startswith(prefix) ]
# print 'doXx > xclasses', xclasses
for xclass in xclasses:
source = xclass()
xclassname = xclass.__name__
target = cls.get(xclassname[len(prefix):])
props = [ prop for prop in dir(source) if not prop.startswith('__')
]
for prop in props:
method = getattr(source, prop)
if hasattr(method, 'im_func') and
method.im_func.func_code.co_argcount == 1:
# print 'doXx > method', method
setattr(target, prop, method())
# necessary to do the following?
'''
newmethod = getattr(target, prop)
f = newmethod.__func__
f.__name__ = method.__name__
'''
else:
msg = 'ERROR ... doXx - INVALID METHOD: %s > %s' %
(xclassname, prop)
print msg
# execute the magic.
doXx()
print 'END'
=== === ===
(not sure if I missed something, because I had to extract this code from my
project)
So far this is working for me, but Massimo and others have the final word.
Thanks and take care,
Carlos