Sahana introduction to the code v2


Published on

  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • S3 is a codename for Sahana Eden Server & Client can be on the same machine Each part needs to be debugged separately: Eclipse works well for the Server-side Python, whilst Firebug is excellent for the generated HTML/CSS/JavaScript JavaScript libraries we use include jQuery & ExtJS
  • You can install the software from the server or from provided packs on USB flash drives Users of other Linux distributions are without step-by-step help currently – contributions welcomed 
  • Launch Eclipse tick Use this as the default & do not ask again, Next Right-click on ‘Resource’ in top-right & close Window menu | Open Perspective | Other | Debug Window menu | Open Perspective | Other | PyDev Open the ‘Debug’ perspective. Window menu | Show View | Expressions Set up the Python Interpreter: Window > Preferences > PyDev > Interpreter - Python New, Browse to python26/python.exe, OK, OK Add a new PyDev Project: File > New > Project > PyDev Project > Next untick Use Default Browse to the web2py directory Give the project a name: eden, Next untick "Create default 'src' folder and add it to the pythonpath" Debug Configuration: Run > Debug Configurations > Python Run Name: Sahana Eden Project: Browse to eden Main Module: Browse to Arguments tab: Program Arguments: -a password Apply, Debug unblock in Windows Firewall
  • Look around the filesystem in web2py/applications/eden folder Similar layout structure to other MVC frameworks, such as Ruby-on-Rails
  • JavaScript which doesn’t require server-side parsing put into static Python Libraries available: System Python, Web2Py, Eden (S3*)
  • Remember that after server-side Python finishes, we still have a lot of possibilities client-side with JavaScript.
  • Minimise the time taken to process Manage dependencies No need to import most of the libraries in ‘gluon/’
  • Deleted Columns / Tables simply Ignored
  • Take a look at them now Remember that execution order is defined by alphabetical order
  • Take a look at them now
  • Take a look at them now
  • For each of these, you should find at least 1 Model, a single Controller & a folder containing 1 or more Views
  • Sahana Eden is Resource-centric
  • Web Services, Mash-ups
  • Create a new file in the Models folder called ‘’ & type in the text above. # Text after this symbol is a comment & is ignored If you make a mistake, then the Ticketing system should catch the error & let you know what you did wrong.
  • No need to create a manual routes entry, unlike other frameworks, like Django
  • Create a new file in the Controllers folder called ‘’ & type in the text above.
  • Note that you’ll need to Register yourself as a user on the system before you’re allowed to create a resource. The 1 st user to register gets the Administrator role by default.
  • This should be available as a script or an alias ‘w2p’
  • No need to learn another macro language Can Extend just a single other file Can Include many others
  • These defaults are why we didn’t need any views for our application.
  • Create a new folder in the views folder called ‘vts’ & inside that put a new file ‘vehicle_list_create.html’. Type in the text above. Refresh the vehicle page to see the new text:
  • All user-visible text should be localised by calling through T() Amend your view & then update the languages files - the string should now be visible in the list of strings to translate
  • HTML tags shouldn’t be in the translatable strings If concatenating with strings, need to str() the LazyT 1 st . Tstr() is a convenience function defined within Eden
  • Open the About page & browse the variables We store our S3 variables in response.s3.*, session.s3.* so as not to pollute the Web2Py namespace
  • Unique=True is a SQL-level constraint. Open your from the models directory & add the extra code above. Try to enter bad data: tickets
  • Validators are DAL-level constraints which produce nice error messages instead of tickets! Validators provide server-side validation & some also provide client-side rendering & validation Add the extra code above to your file & now add bad data to see the difference.
  • Fields default to type ‘string’. ‘ date’ is the SQL-level field type & also provides the class in the HTML which means we get a date widget Add the extra code above to your file & refresh the page, now enter a date.
  • Add the extra code above to your file & refresh the page to see the default value
  • Add this to your controller & try it out
  • You can check out the languages file again, if you wish: Update all languages
  • Add this to your controller & try it out Comment is rendered as ‘column3’ (although can be moved using ‘formstyle’)
  • Try them out…copy/paste from another controller & then edit…see what effect this has on your module.
  • Can provide your own custom buttons here – shn_action_buttons are just the common ones. See definition in models/ Copy this into your controller file & see what effect this has on your module. This REST ‘post-processor’ has a companion ‘pre-processor’ available too (you can see organsiation() for an example)
  • URL() is an example of an HTML ‘Helper’ object
  • Add this text to the file in the models folder. Navigate to the home page to see the module appear both there & on the menu. Try navigating to the module. Module Type 10 means appears in the ‘more’ section of the default modules menu. (Most deployments will create a fully-customised menu anyway)
  • Add this text to your controller file & now open the module. “ Custom View” is a Doc String One should be added to all functions for automatic documentation generators & interactive browsing of docs You can try this out in the Interactive Shell: w2p execfile("applications/eden/controllers/", globals()) help(index)
  • Create a file called ‘index.html’ inside the views/vts folder See plain HTML being interspersed with the server-side parsed Python Look at another module’s index.html What’s bad about this index?
  • Add this text to your controller (outside the functions – e.g. at the top) & see what effect this has on your module.
  • Copt this text into your model. Note the use of string substitution to define the tablename
  • Tells SQL that these fields are ‘reference’ fields (i.e. Foreign Keys) - They store integers which are a pointer to the ID field in the other tables.
  • Copy this text into your Model & refresh the presence page Reusable field defined in models/ Includes additional useful configuration such as .requires & .represent
  • Copt this text into your controller. Try it out. Note the automation of the resource name to minimise the editing after copy/paste of new functions
  • Copy this text into your model & see what it does for the page IS_ONE_OF() will provide us a dropdown showing license plates, even though we actually store the ID. This is an S3 validator which extends Web2Py’s IS_IN_DB() to support the ‘deleted’ status & also allow the use of lambdas as formatting options.
  • We can add additional fields into the link table.
  • Google: web2py dal Try these out in the Web2Py shell  Don’t take effect until you db.commit() Beware locking with Sqlite! (e.g. cron tasks) Wipe DB if developing a lot For Production, split Dev/UAT/Prod instances so that you can plan Data Migrations (Live migrations works in most cases, but some do need manual scripts still – not a complete ‘Get out of jail free’).
  • Don’t take effect until you db.commit()
  • IS_ONE_OF provides the representation in the dropdown table.field.represent provides the representation in Display/List views Optimise the query – we know we only want a single record & a single field from that record
  • Add this to your model underneath the definition of the Presence table & try out the URL. No need for dedicated presence() controller
  • Add this Resource Header to your Controller.
  • Then plug it into the Controller Take another look
  • Add a Vehicle Presence & view it on the Map
  • Can automate the collection of the location information if it makes sense
  • Whilst we spend a lot of time updating developer documentation, the actual codebase always moves faster, so the source is always the most authoritative source of information.
  • Web2Py source code very accessible – small enough to be able to grasp the whole thing after not too long FORM defined in gluon/ Dumb HTML elements SQLFORM defined in gluon/ Self-processing forms which update the database CRUD defined in gluon/ Wrappers around SQLFORM REST defined in modules/ RESTful interface & XML representations If you drop down a level, then need to do things more manually & need to take care of framework issues yourself.
  • NB Don’t redirect in an onaccept or you’ll break bulk XML imports!
  • XSLT stored in static
  • More effort at 1 st but makes subsequent resources much faster to copy/paste
  • S3’s REST Controller is built on top of Web2Py’s ‘Crud’ controller, so we can also use it’s controls NB Be careful using next or you’ll break bulk XML imports!
  • Only want this in interactive views, not JSON/XML & not in Popups either
  • We wrap the underlying CRUD functions within REST
  • Sahana introduction to the code v2

    1. 1. Sahana Eden: Emergency Development Environment 2 July 2010, Sahana Camp Fran Boon [email_address]
    2. 2. Stack Overview <ul><li>Server </li></ul>Client Browser Eclipse Firebug Sahana Eden (S3) Web2Py Python HTML JavaScript CSS
    3. 3. Set yourself up <ul><li> </li></ul><ul><li>Linux: </li></ul><ul><ul><li>sudo su - </li></ul></ul><ul><ul><li> </li></ul></ul><ul><li>Windows: </li></ul><ul><ul><li>unzip to c: </li></ul></ul><ul><ul><li>Eden-Python-Installer-Dev.exe </li></ul></ul><ul><ul><ul><li>c:inpython26 </li></ul></ul></ul><ul><ul><li>jre-6u21-windows-i586.exe </li></ul></ul><ul><ul><li>putty-0.60-installer.exe </li></ul></ul>
    4. 4. Windows: Layout <ul><li>c:in python 26 </li></ul><ul><li>c:in bzr .bat </li></ul><ul><li>c:ingrep.exe </li></ul><ul><li>c:inssh.exe </li></ul><ul><li>c:in eclipse </li></ul><ul><li>c:in w2p.cmd </li></ul><ul><li>c:in web2py applications eden </li></ul><ul><li>Add C:Bin to the system PATH </li></ul><ul><li>Control Panel | System | Advanced | Environment Variables </li></ul><ul><li>C:Bin;… </li></ul>
    5. 5. Configure Eclipse <ul><li>Perspectives </li></ul><ul><li>Python Interpreter </li></ul><ul><li>New PyDev Project </li></ul><ul><ul><li>Web2Py folder </li></ul></ul><ul><li>Debug Configuration </li></ul><ul><ul><li> </li></ul></ul><ul><ul><li>-a password </li></ul></ul>
    6. 6. Tea
    7. 7. Morning Session <ul><li>Model View Controller </li></ul><ul><ul><li>Filesystem Layout </li></ul></ul><ul><li>Web2Py execution model </li></ul><ul><li>S3 REST Controller </li></ul><ul><li>Sahana Modules </li></ul><ul><ul><li>Build a New Module </li></ul></ul>
    8. 8. Model-View-Controller <ul><li>web2py/applications/eden/ </li></ul><ul><ul><li>controllers </li></ul></ul><ul><ul><li>models </li></ul></ul><ul><ul><li>modules </li></ul></ul><ul><ul><li>static </li></ul></ul><ul><ul><li>views </li></ul></ul>
    9. 9. Model-View-Controller <ul><li>Models </li></ul><ul><ul><li>Define Tables in the Database </li></ul></ul><ul><li>Controllers </li></ul><ul><ul><li>Workflow, Logic </li></ul></ul><ul><li>Views </li></ul><ul><ul><li>HTML / JS Templates parsed server-side </li></ul></ul><ul><ul><li>JS functions then run client-side in browser </li></ul></ul>
    10. 10. Model-View-Controller <ul><li>Static </li></ul><ul><ul><li>no server-side processing </li></ul></ul><ul><ul><li>Images </li></ul></ul><ul><ul><li>CSS </li></ul></ul><ul><ul><li>JavaScript </li></ul></ul><ul><li>Modules </li></ul><ul><ul><li>Python libraries </li></ul></ul>
    11. 11. JavaScript
    12. 12. Models <ul><li>All executed every request </li></ul><ul><li>In alphabetical order </li></ul><ul><li>Within web2py environment </li></ul>
    13. 13. Models <ul><li>Define Tables in Database </li></ul><ul><ul><li>Live Migrations: Tables created/altered in database </li></ul></ul><ul><li>Utility functions & variables which are used by multiple controllers </li></ul>
    14. 14. Core Models <ul><li> </li></ul><ul><ul><li>deployment settings for easy customisation </li></ul></ul><ul><li> </li></ul><ul><ul><li>connect to the database </li></ul></ul><ul><ul><li>instantiate classes </li></ul></ul><ul><li> </li></ul><ul><ul><li>read deployment settings & action them </li></ul></ul>
    15. 15. Core Models (continued) <ul><li> </li></ul><ul><ul><li>define some re-usable fields for tables </li></ul></ul><ul><ul><li>define admin tables </li></ul></ul><ul><li> </li></ul><ul><ul><li>patch session </li></ul></ul><ul><ul><li>utility functions </li></ul></ul><ul><li> </li></ul><ul><ul><li>REST Controller front-end </li></ul></ul>
    16. 16. Core Models (continued) <ul><li> </li></ul><ul><ul><li>build the Menus </li></ul></ul><ul><li> </li></ul><ul><ul><li>Import default data on 1 st run (needs all tables defined 1 st ) </li></ul></ul>
    17. 17. Modules <ul><li>Sahana concept </li></ul><ul><ul><li>Logical grouping of user-facing functionality </li></ul></ul><ul><ul><li>Not to be confused with Python modules </li></ul></ul><ul><ul><ul><li>i.e. Not web2py/applications/eden/modules </li></ul></ul></ul><ul><li>Consist of: </li></ul><ul><ul><li>Model(s) </li></ul></ul><ul><ul><li>Controller </li></ul></ul><ul><ul><li>Views </li></ul></ul>
    18. 18. Sahana Modules <ul><li>org - Organisation Registry </li></ul><ul><li>pr - Person Registry </li></ul><ul><li>cr - Shelter Registry </li></ul><ul><li>hms - Hospital Management </li></ul><ul><li>rms - Request Management </li></ul><ul><li>vol – Volunteer Management </li></ul><ul><li>msg - Messaging </li></ul><ul><li>gis - Mapping </li></ul>
    19. 19. Resources <ul><li>person (pr) </li></ul><ul><li>location (gis) </li></ul><ul><li>organisation (org) </li></ul><ul><li>hospital (hms) </li></ul><ul><li>shelter (cr) </li></ul>
    20. 20. S3 REST Controller <ul><li>Args: </li></ul><ul><ul><li>/update, /create, /delete </li></ul></ul><ul><li>HTTP verbs: </li></ul><ul><ul><li>GET, PUT (POST), DELETE </li></ul></ul><ul><li>Representations: </li></ul><ul><ul><li>.html, .json, .xml, .xls, .pdf </li></ul></ul>
    21. 21. eden module resource
    22. 22. Emergency <ul><li>We have to build a module by lunchtime! </li></ul>
    23. 23. Adding a new module <ul><li>Vehicle Tracking System </li></ul><ul><li>Name: vts </li></ul><ul><li>Resources: </li></ul><ul><ul><li>vehicle </li></ul></ul><ul><ul><li>driver </li></ul></ul><ul><ul><li>location </li></ul></ul>
    24. 24. Model: Define Table <ul><li>models/ </li></ul><ul><li># Vehicle resource </li></ul><ul><li>table = db.define_table(&quot;vts_vehicle&quot;, </li></ul><ul><li>Field(&quot;registration&quot;), </li></ul><ul><li>Field(&quot;make&quot;), </li></ul><ul><li>Field(&quot;model&quot;), </li></ul><ul><li>Field(&quot;supplier&quot;), </li></ul><ul><li>) </li></ul>
    25. 25. Controllers <ul><li>Entire Controller is executed </li></ul><ul><ul><li>Manipulation done outside of functions is visible to all functions </li></ul></ul><ul><li>Function which has been called is executed </li></ul><ul><li>Functions with no arguments are automatically visible via URLs </li></ul>
    26. 26. Controller: S3 REST <ul><li>controllers/ </li></ul><ul><li>def vehicle(): </li></ul><ul><li>return shn_ rest _controller(&quot;vts&quot;, &quot;vehicle&quot;) </li></ul>
    27. 27. View <ul><li>None needed at 1st – can RAD without them </li></ul><ul><li>& then polish later  </li></ul><ul><li>Try: </li></ul><ul><li> </li></ul><ul><li>Create a vehicle. </li></ul><ul><li>View in different formats: </li></ul><ul><ul><li>.json, .xml, .xls, .pdf </li></ul></ul>
    28. 28. Morning Session <ul><li>Model View Controller </li></ul><ul><ul><li>Filesystem Layout </li></ul></ul><ul><li>Web2Py execution model </li></ul><ul><li>S3 REST Controller </li></ul><ul><li>Sahana Modules </li></ul><ul><ul><li>Build a New Module </li></ul></ul>
    29. 29. Lunch
    30. 30. Afternoon Session <ul><li>Web2Py Shell </li></ul><ul><li>Views </li></ul><ul><li>Extend our New Module </li></ul><ul><li>Internationalisation </li></ul><ul><li>Menus </li></ul><ul><li>Joined Resources </li></ul><ul><li>DAL: Database Abstraction Layer </li></ul><ul><li>Mapping </li></ul>
    31. 31. Exploring: Web2Py shell <ul><li>Python is great for interactive exploring! </li></ul><ul><ul><li>Web2Py allows this too  </li></ul></ul><ul><li>w2p </li></ul><ul><li>python –S eden –M </li></ul><ul><li>Explore objects with tab </li></ul><ul><li>db. </li></ul><ul><li>gis. </li></ul>
    32. 32. Views: Web2Py <ul><li>Defaults to views/controller/function.html </li></ul><ul><li>Python code inside {{ }} is parsed server-side </li></ul><ul><li>Views can extend & include other views </li></ul><ul><li>Extend ‘ layout ’ for overall look/feel </li></ul><ul><ul><li>{{extend &quot;layout.html&quot;}} </li></ul></ul>
    33. 33. Views: S3 REST <ul><li>REST has defaults </li></ul><ul><ul><li>create.html </li></ul></ul><ul><ul><li>display.html </li></ul></ul><ul><ul><li>list.html </li></ul></ul><ul><ul><li>List_create.html </li></ul></ul><ul><ul><li>update.html </li></ul></ul>
    34. 34. Views: Custom <ul><li>They can also be customised: </li></ul><ul><li>views/vts/vehicle_list_create.html </li></ul><ul><li>{{extend &quot;layout.html&quot;}} </li></ul><ul><li>{{rheader=&quot;Register a new vehicle in the system:&quot;}} </li></ul><ul><li>{{include &quot;_list_create.html&quot;}} </li></ul>
    35. 35. Internationalisation <ul><li>{{rheader= T (&quot;Register a new vehicle in the system:&quot;)}} </li></ul><ul><li> </li></ul><ul><li>Update all languages </li></ul>
    36. 36. Internationalisation <ul><li>Try these in the shell: w2p </li></ul><ul><li>print T(&quot;My Text&quot;) </li></ul><ul><li>print T(&quot;<P>My HTML</P>&quot;) </li></ul><ul><li>print &quot;<P>&quot; + T(&quot;My HTML&quot;) + &quot;</P>&quot; </li></ul><ul><li>print &quot;<P>&quot; + str(T(&quot;My HTML&quot;)) + &quot;</P>&quot; </li></ul><ul><li>print &quot;<P>&quot; + Tstr(&quot;My HTML&quot;) + &quot;</P>“ </li></ul>
    37. 37. Views <ul><li>Variables only visible to views if: </li></ul><ul><li>explicitly passed in return dict() </li></ul><ul><li>stored in global variables: </li></ul><ul><ul><ul><li>request , response , session </li></ul></ul></ul><ul><ul><ul><li> </li></ul></ul></ul>
    38. 38. Model: SQL constraints <ul><li>models/ </li></ul><ul><li>table = db.define_table(&quot;vts_vehicle&quot;, </li></ul><ul><li>Field(&quot;registration&quot;, unique=True ), </li></ul><ul><li>Field(&quot;make&quot;), </li></ul><ul><li>Field(&quot;model&quot;), </li></ul><ul><li>Field(&quot;supplier&quot;), </li></ul><ul><li>) </li></ul>
    39. 39. Model: Validators <ul><li>models/ </li></ul><ul><li>table = db.define_table(&quot;vts_vehicle&quot;, </li></ul><ul><li>Field(&quot;registration&quot;, unique=True), </li></ul><ul><li>Field(&quot;make&quot;), </li></ul><ul><li>Field(&quot;model&quot;), </li></ul><ul><li>Field(&quot;supplier&quot;), </li></ul><ul><li>) </li></ul><ul><li>table.registration. requires = NOT NEEDED! </li></ul><ul><li>IS_NOT_IN_DB(db, table.registration) </li></ul>
    40. 40. Model: Field Types <ul><li>models/ </li></ul><ul><li>table = db.define_table(&quot;vts_vehicle&quot;, </li></ul><ul><li>Field(&quot;registration&quot;, unique=True), </li></ul><ul><li>Field(&quot;make&quot;), </li></ul><ul><li>Field(&quot;model&quot;), </li></ul><ul><li>Field(&quot;purchase_date&quot;, &quot; date &quot;), </li></ul><ul><li>Field(&quot;supplier&quot;), </li></ul><ul><li>) </li></ul>
    41. 41. Model: Default Values <ul><li>models/ </li></ul><ul><li>table = db.define_table(&quot;vts_vehicle&quot;, </li></ul><ul><li>Field(&quot;registration&quot;, unique=True), </li></ul><ul><li>Field(&quot;make&quot;), </li></ul><ul><li>Field(&quot;model&quot;), </li></ul><ul><li>Field(&quot;purchase_date&quot;, &quot;date&quot;, default=request.utcnow ), </li></ul><ul><li>Field(&quot;supplier&quot;), </li></ul><ul><li>) </li></ul>
    42. 42. Controller: Labels <ul><li>controllers/ </li></ul><ul><li>def vehicle(): </li></ul><ul><li>db.vts_vehicle.registration. label = &quot;License Plate&quot; </li></ul><ul><li>return shn_rest_controller(&quot;vts&quot;, &quot;vehicle&quot;) </li></ul>
    43. 43. Controller: Labels <ul><li>controllers/ </li></ul><ul><li>def vehicle(): </li></ul><ul><li>db.vts_vehicle.registration. label = T (&quot;License Plate&quot;) </li></ul><ul><li>return shn_rest_controller(&quot;vts&quot;, &quot;vehicle&quot;) </li></ul>
    44. 44. Controller: Comment <ul><li>controllers/ </li></ul><ul><li>def vehicle(): </li></ul><ul><li>db.vts_vehicle.registration.label = T(&quot;License Plate&quot;) </li></ul><ul><li>db.vts_vehicle.registration. comment = </li></ul><ul><li>SPAN(&quot;*&quot;, _class=&quot;req&quot;) </li></ul><ul><li>return shn_rest_controller(&quot;vts&quot;, &quot;vehicle&quot;) </li></ul>
    45. 45. Controller: CRUD Strings <ul><li>controllers/ </li></ul><ul><li>def vehicle(): </li></ul><ul><li>… </li></ul><ul><li>s3.crud_strings [&quot;vts_vehicle&quot;] = Storage( </li></ul><ul><li>title_create = T(&quot;Add Vehicle&quot;), </li></ul><ul><li> title_display = T(&quot;Vehicle Details&quot;), </li></ul><ul><li> title_list = T(&quot;List Vehicles&quot;), </li></ul><ul><li> title_update = T(&quot;Edit Vehicle&quot;), </li></ul><ul><li> label_create_button = T(&quot;Add Vehicle&quot;), </li></ul><ul><li> msg_record_created = T(&quot;Vehicle added&quot;), </li></ul><ul><li>… </li></ul><ul><li>) </li></ul><ul><li>… </li></ul>
    46. 46. Controller: Action buttons <ul><li>controllers/ </li></ul><ul><li>def vehicle(): </li></ul><ul><li>… </li></ul><ul><li>def veh_postp(jr, output): shn_action_buttons (jr) </li></ul><ul><li>return output </li></ul><ul><li>response.s3.postp = veh_postp </li></ul><ul><li>output = shn_rest_controller(&quot;vts&quot;, &quot;vehicle&quot;) </li></ul><ul><li>return output </li></ul>
    47. 47. How do we Navigate? <ul><li>Modules menu </li></ul><ul><li>Modules list on frontpage </li></ul><ul><li>Menu within Module </li></ul>
    48. 48. URL(r=request, a= application , c= controller , f= function , args=[], vars={})
    49. 49. Enable Module <ul><li>models/ </li></ul><ul><li>deployment_settings.modules = Storage( </li></ul><ul><li>… </li></ul><ul><li>vts = Storage( </li></ul><ul><li>name_nice = &quot;Vehicle Tracking System&quot;, description = &quot;Track vehicles&quot;, </li></ul><ul><li> module_type = 10 </li></ul><ul><li>), </li></ul><ul><li>… </li></ul><ul><li>) </li></ul>
    50. 50. Index page <ul><li>controllers/ </li></ul><ul><li>module = request.controller </li></ul><ul><li>def index(): </li></ul><ul><li>&quot;Custom View&quot; </li></ul><ul><li>module_name = deployment_settings.modules[module].name_nice </li></ul><ul><li>return dict(module_name=module_name) </li></ul>
    51. 51. View <ul><li>views/vts/index.html </li></ul><ul><li>{{extend &quot;layout.html&quot;}} </li></ul><ul><li>{{=H2(T(module_name))}} </li></ul><ul><li><p>This module allows users to track their vehicles</p> </li></ul><ul><li>{{=LI(A(&quot;List Vehicles&quot;, _href=URL(r=request, f=&quot;vehicle&quot;)))}} </li></ul>
    52. 52. Controller: Menu <ul><li>controllers/ </li></ul><ul><li>response.menu_options = [ </li></ul><ul><li>[T(&quot;Vehicles&quot;), False, URL(r=request, f=&quot;vehicle&quot;),[ [ T(&quot;List&quot;), False, URL(r=request, f=&quot;vehicle&quot;)], [T(&quot;Add&quot;), False, URL(r=request, f=&quot;vehicle&quot;, args=&quot;create&quot;)] ]]] </li></ul>
    53. 53. Tea
    54. 54. Joined Resources <ul><li>So far: </li></ul><ul><ul><li>Resource = Single Table </li></ul></ul><ul><li>Reality: </li></ul><ul><ul><li>Resource spread out over multiple Tables </li></ul></ul>
    55. 55. Joined Resources: Model <ul><li>Link Vehicle to Location </li></ul><ul><ul><li>vts_presence </li></ul></ul>
    56. 56. Joined Resources: Model <ul><li>models/ </li></ul><ul><li>module = &quot;vts&quot; </li></ul><ul><li>resource = &quot;presence&quot; </li></ul><ul><li>tablename = &quot;%s_%s&quot; % (module, resource) </li></ul><ul><li>table = db.define_table(tablename, </li></ul><ul><li>Field(&quot;vehicle_id&quot;), </li></ul><ul><li>Field(&quot;location_id&quot;), </li></ul><ul><li>) </li></ul>
    57. 57. Joined Resources: Model <ul><li>models/ </li></ul><ul><li>table = db.define_table(tablename, </li></ul><ul><li>Field(&quot;vehicle_id&quot;, db.vts_vehicle), </li></ul><ul><li>Field(&quot;location_id&quot;, db.gis_location), </li></ul><ul><li>) </li></ul>
    58. 58. Joined Resources: Model <ul><li>models/ </li></ul><ul><li>table = db.define_table(tablename, </li></ul><ul><li>Field(&quot;vehicle_id&quot;, db.vts_vehicle), </li></ul><ul><li>location_id , </li></ul><ul><li>) </li></ul>
    59. 59. Joined Resources: Controller <ul><li>controllers/ </li></ul><ul><li>def presence (): </li></ul><ul><li>resource = request.function </li></ul><ul><li>return shn_rest_controller(module, resource) </li></ul><ul><li> </li></ul>
    60. 60. Joined Resources: Model <ul><li>models/ </li></ul><ul><li>table = db.define_table(tablename, </li></ul><ul><li>Field(&quot;vehicle_id&quot;, db.vts_vehicle), </li></ul><ul><li>location_id, </li></ul><ul><li>) </li></ul><ul><li>table.vehicle_id. requires = IS_ONE_OF (db, </li></ul><ul><li>&quot;;, </li></ul><ul><li>&quot;vts_vehicle.registration&quot;) </li></ul>
    61. 61. Joined Resources: Model <ul><li>models/ </li></ul><ul><li>table = db.define_table(tablename, </li></ul><ul><li>Field(&quot;vehicle_id&quot;, db.vts_vehicle), </li></ul><ul><li>location_id, </li></ul><ul><li>Field(&quot;time&quot;, &quot;datetime&quot;) , </li></ul><ul><li>) </li></ul><ul><li>table.vehicle_id.requires = IS_ONE_OF(db, &quot;;, &quot;vts_vehicle.registration&quot;) </li></ul><ul><li>table.time.requires = IS_DATETIME() </li></ul>
    62. 62. DAL: Database Abstraction Layer <ul><li>SQLite </li></ul><ul><ul><ul><li>out of the box </li></ul></ul></ul><ul><li>MySQL </li></ul><ul><ul><ul><li>well-tested with Eden </li></ul></ul></ul><ul><li>PostgreSQL </li></ul><ul><ul><ul><li>what we want to use for Spatial support </li></ul></ul></ul><ul><li>Oracle, DB2, MS SQL, Firebird, GAE </li></ul>
    63. 63. DAL <ul><li>Try these in the shell: w2p </li></ul><ul><li>db.define_table(&quot;person&quot;, Field(&quot;name&quot;)) </li></ul><ul><li>id = db.person.insert(name=&quot;max&quot;) query = ( == id) </li></ul><ul><li>db(query).count() </li></ul><ul><li>db(query).update(name=&quot;Max&quot;) </li></ul><ul><li>rows = db(query).select( for row in rows: </li></ul><ul><li>print </li></ul><ul><li>db(query).delete() </li></ul>
    64. 64. DAL <ul><li>For shell scripts (e.g. Cron tasks): </li></ul><ul><li>db.commit() </li></ul><ul><li>Beware locking (SQLite) </li></ul>
    65. 65. JR: Represent <ul><li>models/ </li></ul><ul><li>table.vehicle_id. represent = lambda id: db( == id). select().first().registration </li></ul><ul><li>table.vehicle_id.represent = lambda id: db( == id). select( limitby =(0,1)).first().registration </li></ul><ul><li>table.vehicle_id.represent = lambda id: db( == id). select( db.vts_vehicle.registration , limitby=(0,1)).first().registration </li></ul>
    66. 66. JR: Components <ul><li>models/ </li></ul><ul><li># Presence as component of vehicle </li></ul><ul><li>s3xrc.model.add_component(module, </li></ul><ul><li>resource, </li></ul><ul><li>multiple=True, </li></ul><ul><li>joinby=dict(vts_vehicle=&quot;vehicle_id&quot;), </li></ul><ul><li>deletable=True, </li></ul><ul><li>editable=True) </li></ul><ul><li> </li></ul>
    67. 67. Components: RHeader <ul><li>controllers/ </li></ul><ul><li>def shn_vts_rheader(jr, tabs=[]): </li></ul><ul><li>if jr.representation == &quot;html&quot;: </li></ul><ul><li>rheader_tabs = shn_rheader_tabs(jr, tabs) </li></ul><ul><li>vehicle = jr.record </li></ul><ul><li>rheader = DIV(TABLE( </li></ul><ul><li>TR(TH(T(&quot;Vehicle: &quot;)), vehicle.registration, </li></ul><ul><li>TH(T(&quot;Make: &quot;)), vehicle.make), </li></ul><ul><li>TR(TH(T(&quot;Purchase Date: &quot;)), </li></ul><ul><li>vehicle.purchase_date, </li></ul><ul><li>TH(T(&quot;Model: &quot;)), vehicle.model)), </li></ul><ul><li>rheader_tabs) </li></ul><ul><li>return rheader </li></ul><ul><li>return None </li></ul>
    68. 68. Components: Rheader Tabs <ul><li>controllers/ </li></ul><ul><li>def vehicle(): </li></ul><ul><li>… </li></ul><ul><li>output = shn_rest_controller(module, &quot;vehicle&quot;, </li></ul><ul><li>rheader=lambda jr: shn_vts_rheader(jr, </li></ul><ul><li>tabs = [(T(&quot;Basic Details&quot;), None), </li></ul><ul><li>(T(&quot;Presence&quot;), &quot;presence&quot;) </li></ul><ul><li>]), </li></ul><ul><li>sticky=True) </li></ul><ul><li>return output </li></ul><ul><li> </li></ul>
    69. 69. Show me the Map!
    70. 70. Map <ul><li>Different Layers: </li></ul><ul><li>Base </li></ul><ul><li>Overlay </li></ul><ul><ul><li>Internal </li></ul></ul><ul><ul><li>External (Earthquakes) </li></ul></ul>
    71. 71. Display on Map <ul><li>Map displays Feature Groups </li></ul><ul><li>Feature Groups contain Feature Classes </li></ul><ul><li>Locations have Feature Classes </li></ul><ul><li>“ Vehicles” are set up ready to go  </li></ul>
    72. 72. Simplify data entry: GIS Controller <ul><li>controllers/ </li></ul><ul><li>def location() </li></ul><ul><li>… </li></ul><ul><li>if &quot;vts_presence&quot; in caller: </li></ul><ul><li>fc = db( == &quot;Vehicle&quot;). select(, limitby=(0, 1)).first() </li></ul><ul><li>… </li></ul>
    73. 73. Simplify data entry: GIS View <ul><li>views/gis/location_popup.html </li></ul><ul><li>… </li></ul><ul><li>{{elif &quot;vts_presence&quot; in request.vars.caller:}} </li></ul><ul><li>// If coming from the VTS then populate defaults for the // fields & Hide unnecessary rows </li></ul><ul><li>var location_name = self.parent. $('#vts_presence_vehicle_id__row > td.w2p_fw').html(); </li></ul><ul><li>if (location_name) { $(&quot;#gis_location_name&quot;).val(location_name); //$(&quot;#gis_location_name__row&quot;).hide(); </li></ul><ul><li>} </li></ul><ul><li>… </li></ul>
    74. 74. HTML5 Geolocation <ul><li>views/gis/location_popup.html </li></ul><ul><li>… </li></ul><ul><li>{{elif &quot;vts_presence&quot; in request.vars.caller:}} </li></ul><ul><li>… </li></ul><ul><li>if (navigator.geolocation){ </li></ul><ul><li>navigator.geolocation.getCurrentPosition(getCurrentPosition); </li></ul><ul><li>} </li></ul><ul><li>… </li></ul>
    75. 75. Documentation <ul><li>Examples from other modules </li></ul><ul><li>Developer Guidelines on Wiki: </li></ul><ul><li> </li></ul><ul><li>But the best…? </li></ul>
    76. 76. Use the Source, Luke! <ul><li>Many resources and tricks on the Internet find you will, but the ultimate answers only in the source lie </li></ul>
    77. 77. S3 is built on Web2Py REST CRUD SQLFORM FORM
    78. 78. Form submission <ul><li>Use Firebug’s Net Panel to look at a form submission. </li></ul><ul><li>Each field has an entry in form.vars </li></ul><ul><li>Can add additional vars to the form in a custom View </li></ul><ul><li>Can process these within our Controller </li></ul><ul><ul><li>onvalidation: Before DB I/O </li></ul></ul><ul><ul><li>onaccept: After DB I/O </li></ul></ul>
    79. 79. Web2Py CRUD <ul><li>web2py/gluon/ </li></ul><ul><li>self.settings.create_onvalidation = None self.settings.update_onvalidation = None self.settings.delete_onvalidation = None self.settings.create_onaccept = None self.settings.update_onaccept = None self.settings.update_ondelete = None self.settings.delete_onaccept = None </li></ul><ul><li>onvalidation: Before DB I/O </li></ul><ul><li>onaccept: After DB I/O </li></ul>
    80. 80. S3XRC <ul><li>Export </li></ul><ul><ul><li>1 st build native XML tree </li></ul></ul><ul><ul><li>Then transform to output format using XSLT </li></ul></ul><ul><li>Import </li></ul><ul><ul><li>1st transform the input format using XSLT </li></ul></ul><ul><ul><li>Then import native XML tree </li></ul></ul>
    81. 81. Afternoon Session <ul><li>Web2Py Shell </li></ul><ul><li>Views </li></ul><ul><li>Extend our New Module </li></ul><ul><li>Internationalisation </li></ul><ul><li>Menus </li></ul><ul><li>Joined Resources </li></ul><ul><li>DAL: Database Abstraction Layer </li></ul><ul><li>Mapping </li></ul>
    82. 82. End
    83. 83. Controller: String Substitution <ul><li>controllers/ </li></ul><ul><li>module = request.controller </li></ul><ul><li>def vehicle(): </li></ul><ul><li>resource = request.function </li></ul><ul><li>tablename = &quot;%s_%s&quot; % (module, resource) </li></ul><ul><li>table = db[tablename] </li></ul><ul><li>return shn_rest_controller(module, resource) </li></ul>
    84. 84. Web2Py CRUD <ul><li>web2py/gluon/ </li></ul><ul><li>self.settings.create_next = None </li></ul><ul><li>self.settings.update_next = None </li></ul>
    85. 85. Controller: prep <ul><li>controllers/ </li></ul><ul><li>def organisation(): </li></ul><ul><li>… </li></ul><ul><li>def org_prep(jr): </li></ul><ul><li>if jr.representation == &quot;html&quot;: </li></ul><ul><li>crud.settings.create_next = URL(r=request, f=&quot;dashboard&quot;) crud.settings.update_next = URL(r=request, f=&quot;dashboard&quot;) </li></ul><ul><li> return True </li></ul><ul><li>response.s3.prep = org_prep </li></ul><ul><li>output = shn_rest_controller(module, resource) </li></ul><ul><li>return output </li></ul>
    86. 86. S3 REST <ul><li>models/ </li></ul><ul><li>table = db.gis_location </li></ul><ul><li>s3xrc.model.configure( </li></ul><ul><li>table, </li></ul><ul><li>onvalidation = lambda form: gis.wkt_centroid(form), </li></ul><ul><li>onaccept = gis.update_location_tree() </li></ul><ul><li>) </li></ul>
    87. 87. BluePrint: Messaging Open Data Kit JavaRosa