| 48 | | == Sahana3 Framework == |
| 49 | | We have built an S3 framework as a higher level of abstraction on top of T2.[[BR]] |
| 50 | | This should be used by modules where possible, but if more power is needed then drop down a level of two (to T2, to base Web2Py or to raw Python). |
| 51 | | |
| 52 | | T2 is used for: |
| 53 | | * [wiki:DeveloperGuidelinesAuthenticationAccess AAA] |
| 54 | | * simplified [wiki:DeveloperGuidelinesCreateReadUpdateDelete CRUD] |
| 55 | | * Conflict Detection) |
| 56 | | We extend the T2 class in {{{modules/sahana.py}}} |
| 57 | | |
| 58 | | Populate the side navigation Menus by adding this to each controller: |
| 59 | | {{{ |
| 60 | | module='module' |
| 61 | | # Current Module (for sidebar title) |
| 62 | | module_name=db(db.module.name==module).select()[0].name_nice |
| 63 | | # List Modules (from which to build Menu of Modules) |
| 64 | | modules=db(db.module.enabled=='Yes').select(db.module.ALL,orderby=db.module.menu_priority) |
| 65 | | # List Options (from which to build Menu for this Module) |
| 66 | | options=db(db['%s_menu_option' % module].enabled=='Yes').select(db['%s_menu_option' % module].ALL,orderby=db['%s_menu_option' % module].priority) |
| 67 | | }}} |
| 68 | | |
| 69 | | Each function needs to return these values to the view: |
| 70 | | return dict(module_name=module_name,modules=modules,options=options) |
| 71 | | |
| 72 | | List output can be made more functional by this .represent 'widget': |
| 73 | | {{{ |
| 74 | | def shn_list_item(table,resource,action,display='table.name',extra=None): |
| 75 | | if extra: |
| 76 | | items=DIV(TR(TD(A(eval(display),_href=t2.action(resource,[action,table.id]))),TD(eval(extra)))) |
| 77 | | else: |
| 78 | | items=DIV(A(eval(display),_href=t2.action(resource,[action,table.id]))) |
| 79 | | return DIV(*items) |
| 80 | | }}} |
| 81 | | You can use it in {{{models/module.py}}} like: |
| 82 | | {{{ |
| 83 | | db.or_organisation.represent=lambda table:shn_list_item(table,resource='organisation',action='display') |
| 84 | | db.person.represent=lambda table:shn_list_item(table,resource='person',action='display',display='table.full_name') |
| 85 | | db.gis_projection.represent=lambda table:shn_list_item(table,resource='projection',action='display',extra='table.epsg') |
| 86 | | }}} |
| 87 | | |
| 88 | | Form labels can be set in a translatable manner using: |
| 89 | | {{{db.table.field.label=T("label")}}} |
| 90 | | |
| 91 | | Form field can be made to use a TEXTAREA by marking the field as being type 'text': |
| 92 | | {{{SQLField('field','text'),}}} |
| 93 | | |
| 94 | | Form field can be made to use a SELECT dropdown by setting the field as a lookup to another table...linked to the 'uuid' field to allow [wiki:DeveloperGuidelinesDatabaseSynchronization Database Synchronization], but displaying a more user-friendly field (such as 'name'): |
| 95 | | {{{ |
| 96 | | SQLField('field',length=64), |
| 97 | | |
| 98 | | db.table.field.requires=IS_NULL_OR(IS_IN_DB(db,'othertable.uuid','othertable.name')) |
| 99 | | }}} |
| 100 | | |
| 101 | | Form field being required can be marked using: |
| 102 | | {{{db.table.field.comment=SPAN("*",_class="req")}}} |
| 103 | | |
| 104 | | Help for a form field can be set using: |
| 105 | | {{{A(SPAN("[Help]"),_class="popupLink",_id="tooltip",_title=T("Help Title|This is what this field is for."))}}} |
| 106 | | |
| 107 | | Different Flash styles can be set via: |
| 108 | | {{{ |
| 109 | | session.error=T("Unsupported format!") |
| 110 | | redirect(URL(r=request,f=resource)) |
| 111 | | }}} |
| 112 | | or (in a Multiple Table form.accepts): |
| 113 | | {{{ |
| 114 | | response.error=T("Form invalid!") |
| 115 | | }}} |
| 116 | | Supported styles are: |
| 117 | | * .warning |
| 118 | | * .error |
| 119 | | * .information |
| 120 | | * .confirmation (Standard T2 Flash messages are usually of this sort so we class them in the same way) |
| 121 | | |
| 122 | | === jQuery Widgets === |
| 123 | | DeveloperGuidelinesDeletableList |
| 124 | | |
| 125 | | === Options fields === |
| 126 | | Sahana2 has a generic 'field_options' table for storing Options fields. |
| 127 | | |
| 128 | | Sahana3 uses a separate table for each lookup list. |
| 129 | | |
| 130 | | === Conflict Detection === |
| 131 | | Sahana is a multi-user system so there is a potential for multiple users to be editing the same record at once.[[BR]] |
| 132 | | We use T2 to handle this for us. |
| 133 | | |
| 134 | | Add this field to each table which needs protecting (in {{{models/db.py}}}): |
| 135 | | {{{ |
| 136 | | SQLField('modified_on','datetime'), # Used by T2 to do edit conflict-detection |
| 137 | | }}} |
| 138 | | |
| 139 | | This field is also used in [wiki:DeveloperGuidelinesDatabaseSynchronization Database Synchronization] |
| 140 | | |
| | 47 | * [wiki:DeveloperGuidelinesSahana3Framework Sahana3 Framework] |
| | 48 | * [wiki:DeveloperGuidelinesSahana2Migration Help for Sahana2 Developers] |