This is cool. I think your TimeClock example is essentially the pattern used for the web2py Mail, Auth, and Crud classes. It might be useful to include a section in the book about this pattern (or at least a web2py slice). Anthony
On Monday, February 28, 2011 11:14:04 AM UTC-5, Ross Peoples wrote: > I've always read that if you needed to centralize your logic, that you > should use modules instead of trying to do it in a model or trying to wire > up one controller to another. I used global settings as an example, as you > might need access to these settings in every controller, and duplicating the > code in every controller goes against the Python and we2py's DRY > (don't repeat yourself) principal. So this is why modules were created. > > Granted, the GlobalSettings object I demonstrated is a very basic object > that doesn't require you to instantiate it because it's all static. However, > if you want to use more sophisticated objects, then the static class method > may not work well. So there's another way to do this that I've been playing > with. > > I am replacing a legacy application that is sort of like an ERP. The > application keeps track of when employees clock in and clock out. Then, at > the end of the week they print out their time cards. So, I wrote a TimeClock > class in the same 'core.py' file described above. The big difference here is > that the TimeClock object will have several functions, and I don't want to > have to pass db, cache, and everything else for every function call, so I > wrote it like this: > > class TimeClock: > def __init__(self, environment, db): > self.env = Storage(environment) > self.request = self.env.request > self.response = self.env.response > self.cache = self.env.cache > self.db = db > > def is_employee_clocked_in(self, employee): > db = self.db > timeclock_entry = db((db.timeclock.employee==employee) & > (db.timeclock.endtime==None)).select().first() > if timeclock_entry is None: > return False > else: > return True > > Now, in my 'z_import_modules.py', I would add this (assuming I already did > a local_import on core.py): > > timeclock = core.TimeClock(globals(), db) > > Then in any controller, if I want to check if an employee is clocked in: > > employee = auth.user > if timeclock.is_employee_clocked_in(employee): > print '%s is clocked in' % (employee.first_name) > else: > print '%s is not clocked in' % (employee.first_name) > > So with modules, you can make static classes for simple objects, like > global settings that just load and save settings, or you can make complex > objects that you instantiate in either the 'z_import_modules.py' file, or if > you don't plan on using the module in every controller, then you could just > remove the line we added in 'z_import_modules.py' to instantiate the > 'timeclock' object, and use that line in whatever controller action we want. > > Hope this helps. So far this method seems to work really well. Oh, and to > help you avoid some frustration in developing your modules, when you call > local_import, you may also want to add reload=True to it. Without this, you > would have to restart the web2py server every time you made a change to the > module. Once you put your app into production, you would want to remove > reload=True, as you don't want web2py to reload the module for every page > load on a production server. So for testing, use this line: > > core = local_import('core', reload=True) > > And when you go into production, just remove 'reload=True'. >