Web2Py: * http://mdp.cti.depaul.edu/examples/static/cookbook.pdf * http://mdp.cti.depaul.edu/examples/static/web2py_cheatsheet.pdf MVC (like Rails) Model Defines databases in: /models/db.py (equivalent of inst/mysql-dbcreate.sql) Controller Python functions in /controllers/module.py e.g. def list_records(): list=t2.itemize(table) return dict (list=list) View HTML/Javascript templates in /views/module/function.html - these are normal HTML/JS files with the ability to add in Python code (e.g. variables) surrounded by brackets: {{ interpreted python here }} - there should be an .html file available for each function in the module (name normally being the same as the function) - if there is no view defined then a default view will be displayed, which will show the values of all the data it can see, but not be formatted nicely CSS/Javascript files are stored in /static (equivalent of www/res) Python: * Slow start - http://openbookproject.net/thinkcs/python/english2e/ * Quick start - http://diveintopython.org/ * v.Quick start! Indentation matters (use 4 spaces instead of Tabs) OOP - everything is an object T2 is used for AAA & simplified CRUD (inc Conflict Detection) http://mdp.cti.depaul.edu/examples/static/t2.pdf We extend the T2 class in modules/sahana.py CRUD Create Record: Controller def add_record(): form=t2.create(db.table) return dict(form=form) View views/module/add_record.html {{=form}} Display Record: Controller def display_record(): item=t2.display(db.table) return dict(item=item) View views/module/display_record.html {{=item}} Update Record: Controller def display_record(): form=t2.update(db.table) return dict(form=form) View views/module/add_record.html {{=form}} Delete Record: Controller def delete_record(): db(db.table.id==t2.id).delete() response.confirmation=T("Record deleted") response.view="module/list_records.html" View normally not used (reuse existing list_records view) Populate the side navigation Menus by adding this to each controller: module='module' # Current Module (for sidebar title) module_name=db(db.module.name==module).select()[0].name_nice # List Modules (from which to build Menu of Modules) modules=db(db.module.enabled=='Yes').select(db.module.ALL,orderby=db.module.menu_priority) # List Options (from which to build Menu for this Module) options=db(db['%s_menu_option' % module].enabled=='Yes').select(db['%s_menu_option' % module].ALL,orderby=db['%s_menu_option' % module].priority) Each function needs to return these values to the view: return dict(module_name=module_name,modules=modules,options=options) List output can be made more functional by adding this to your table definitions in models/db.py: db.table.represent=lambda table: A(table.display_field,_href=t2.action('display_table',table.id)) Form labels can be set in a translatable manner using: db.table.field.label=T("label") Form field can be made to use a TEXTAREA by marking the field as being type 'text': SQLField('field','text'), Form field can be made to use a SELECT dropdown by setting the field as a lookup to another table: SQLField('field',db.othertable), Set this to use a different field than 'id' in the views (e.g. 'name') using: db.table.field.requires=IS_NULL_OR(IS_IN_DB(db,'othertable.id','othertable.name')) Form field being required can be marked using: db.table.field.comment=SPAN("*",_class="req") Help for a form field can be set using: A(SPAN("[Help]"),_class="popupLink",_id="tooltip",_title=T("Help|This is what this field is for.")) Conflict Detection: Add this field to each table which needs protecting (in models/db.py): SQLField('modified_on','datetime'), # Used by T2 to do edit conflict-detection AAA Controller Each controller which incldues protected functions needs this: def login(): response.view='login.html' return dict(form=t2.login()) def logout(): t2.logout(next='login') def register(): response.view='register.html' return dict(form=t2.register()) Each protected function needs this: @t2.requires_login('login') def function(): How to add a new module? - copy existing & edit! Model Add module to db.module: http://127.0.0.1:8000/sahana/appadmin/select/db?query=db.module.id%3E0 Create a table to store the module's menu options to /models/db.py db.module_menu_option Add tables to /models/db.py Controller Add CRUD functions for these tables to /views/module.py View Add HTML templates for these functions: /views/module/function.html How to do Options fields? Sahana2 has a generic 'field_options' table for storing Options fields/. Sahana3 uses a separate table for each lookup list Advanced Tricks: * Python debugging - use Web2Py shell: http://www.vimeo.com/879939 - http://docs.python.org/library/doctest.html - http://docs.python.org/library/bdb.html * CSS & Javascript debugging - use Firebug: http://code.google.com/support/bin/answer.py?answer=77412&topic=12044 * jQuery: - http://www.tvidesign.co.uk/blog/improve-your-jquery-25-excellent-tips.aspx * Ext: - http://extjs.com/learn/Tutorial:Introduction_to_Ext_2.0 - http://extjs.com/learn/Manual:Basic_Application_Design - http://extjs.com/forum/showthread.php?t=26728 - http://extjs.com/learn/Ext_FAQ_Debugging