ghc
DESCRIPTION
Facilitator Training http://eden.sahanafoundation.org/wiki/GHC2010TRANSCRIPT
Sahana Eden:Emergency
Development Environment
15 September 2010, Grace Hopper Celebration
Fran Boon
Agenda
• Stack Overview• Getting Set up• Model View Controller
– Filesystem Layout
• Web2Py execution model• S3 REST Controller• Sahana Modules
– Build a New Module
Stack OverviewServer
Sahana Eden (S3)
Web2Py
Python
HTML
JavaScript
CSS
Client Browser
Eclipse Firebug
Installation: Virtual Machine
Simplest way to start:http://eden.sahanafoundation.org/wiki/InstallationGuidelinesVirtualMachine
Full Developer Environment:•Eclipse•Codebase (Web2Py/Sahana Eden)
Launch Eclipse to get started…
Model-View-Controller
web2py/applications/eden/
•controllers
•models
•views
Model-View-Controller• Models
– Define Tables in the Database
• Controllers– Workflow, Logic
• Views– HTML / JS Templates parsed server-side– JS functions then run client-side in browser
Model-View-Controller
• Static– no server-side processing– Images– CSS– JavaScript
• Modules– Python libraries
Modules• Sahana concept
– Logical grouping of user-facing functionality– Not to be confused with Python modules
• i.e. not web2py/applications/eden/modules
• Consist of:– Model(s)– Controller– Views
Sahana Modules• pr - Person Registry
• org - Organisation Registry
• gis - Mapping
• msg - Messaging
• cr - Shelter Registry
• hms - Hospital Management
• rms - Request Management
• vol – Volunteer Management
Request processing
1. Web2Py environment setup
2. All Models executed
3. Controller executed
4. Controller Function executed
5. View parsed
6. HTML returned to browser
eden module resource
Emergency• We have to build a module before bed!
Adding a new module
• Vehicle Tracking System
• Name: vts• Resources:
– vehicle– driver– location
Model: Define Table
models/vts.py
# Vehicle resource
table = db.define_table("vts_vehicle",
Field("registration"),
Field("make"),
Field("model"),
Field("supplier"),
)
Controllers
• Entire Controller is executed– Manipulation done outside of functions is visible
to all functions
• Function which has been called is executed
• Functions with no arguments are automatically visible via URLs
Controller: S3 REST
controllers/vts.py
def vehicle():
return shn_rest_controller("vts", "vehicle")
View
None needed at 1st – can RAD without them
& then polish later
Try:
http://127.0.0.1:8000/eden/vts/vehicle
1.Create a vehicle.
2.View in different formats:– .json, .xml, .xls, .pdf
http://127.0.0.1:8000/eden/vts/vehicle/1.json
S3 REST Controller• GET args:
– /read, /create , /update, /delete
• HTTP verbs:– GET, PUT (POST), DELETE
• Representations:– .html, .json, .xml, .xls, .pdf
Models
• All executed every request
• In alphabetical order
• Within web2py environment
Models
• Define Tables in Database– Live Migrations:
Tables created/altered in database
• Utility functions & variables which are used by multiple controllers
Core Models
• 000_config.py– deployment settings for easy customisation
• 00_db.py– connect to the database– instantiate classes
• 00_settings.py– read deployment settings & action them
Core Models (continued)• 00_tables.py
– define some re-usable fields for tables– define admin tables
• 00_utils.py– patch session– utility functions
• 01_crud.py– REST Controller front-end
Core Models (continued)
• 01_menu.py– build the Menus
• zzz_1st_run.py– Import default data on 1st run
(needs all tables defined 1st)
Views: S3 REST
• REST has defaults– create.html– display.html– list.html– List_create.html– update.html
Views: Web2Py• Python code inside {{ }} is parsed server-
side
• Views can extend & include other views
• Extend ‘layout’ for overall look/feel{{extend "layout.html"}}
• Defaults (non-REST) to views/controller/function.html
Views: Custom
• REST views can be customised: views/vts/vehicle_list_create.html
{{extend "layout.html"}}
{{rheader="Register a new vehicle in the system:"}}
{{include "_list_create.html"}}
ViewsVariables only visible to views if:
•explicitly passed in return dict()
•stored in global variables:•request, response, session
http://127.0.0.1:8000/eden/default/about
SQL constraints / Validators
models/vts.py
table = db.define_table("vts_vehicle",
Field("registration", unique=True),
Field("make"),
Field("model"),
Field("supplier"),
)
Field Types models/vts.py
table = db.define_table("vts_vehicle",
Field("registration", unique=True),
Field("make"),
Field("model"),
Field("purchase_date", "date"),
Field("supplier"),
)
Default Values
models/vts.py
table = db.define_table("vts_vehicle",
Field("registration", unique=True),
Field("make"),
Field("model"),
Field("purchase_date", "date", default=request.utcnow),
Field("supplier"),
)
Labels models/vts.py
table.registration.label = "License Plate"
Internationalisation models/vts.py
table.registration.label = T("License Plate")
Comments models/vts.py
table.registration.comment = SPAN("*", _class="req")
CRUD Strings controllers/vts.pydef vehicle():
…
s3.crud_strings["vts_vehicle"] = Storage(
title_list = T("List Vehicles"),
label_create_button = T("Add Vehicle"),
msg_record_created = T("Vehicle added"),
)
…
Exploring: Web2Py shell• Python is great for interactive exploring!
– Web2Py allows this too
w2p
python web2py.py –S eden –M
• Explore objects with tabdb.
gis.
LaunchPad
Merge proposal
Branches
Trunk
Local Branch
Your Branch
bzr merge
bzr push
URL(a=application, c=controller, f=function, args=[], vars={})
Enable Module models/000_config.py
deployment_settings.modules = Storage(
…
vts = Storage(
name_nice = "Vehicle Tracking System", description = "Track vehicles",
module_type = 10
),
…
)
Index page controllers/vts.py
module = request.controller
def index():
"Custom View"
module_name = \ deployment_settings.modules[module].name_nice
return dict(module_name=module_name)
View
views/vts/index.html
{{extend "layout.html"}}
{{=H2(T(module_name))}}
<p>This module allows users to track their vehicles</p>
{{=LI(A("List Vehicles", _href=URL(r=request, f="vehicle")))}}
Controller: Menu controllers/vts.py
response.menu_options = [
[T("Vehicles"), False, URL(r=request, f="vehicle"),[[T("List"), False, URL(r=request, f="vehicle")],
[T("Add"), False, URL(r=request, f="vehicle", args="create")] ]]]
DAL:Database Abstraction Layer• SQLite
• out of the box
• MySQL• well-tested with Eden
• PostgreSQL• what we want to use for Spatial support
• Oracle, DB2, MS SQL, Firebird, GAE
DALTry these in the shell: w2p
db.define_table("person", Field("name"))
id = db.person.insert(name="max")query = (db.person.id == id)
db(query).count()
db(query).update(name="Max")
rows = db(query).select(orderby=db.person.name)for row in rows:
print row.name
db(query).delete()
DAL
• For shell scripts (e.g. Cron tasks):
db.commit()
• Beware locking with SQLite
Joined Resources
• So far:– Resource = Single Table
• Reality:– Resource spread out over multiple Tables
Joined Resources: Model
• Link Vehicle to Location– vts_presence
Joined Resources: Model
models/vts.pymodule = "vts"
resource = "presence"
tablename = "%s_%s" % (module, resource)
table = db.define_table(tablename,
Field("vehicle_id"),
Field("location_id"),
)
Joined Resources: Model
models/vts.py
table = db.define_table(tablename,
Field("vehicle_id", db.vts_vehicle),
Field("location_id", db.gis_location),
)
Joined Resources: Model
models/vts.py
table = db.define_table(tablename,
Field("vehicle_id", db.vts_vehicle),
location_id,
)
Joined Resources: Controller controllers/vts.py
def presence():
resource = request.function
return shn_rest_controller(module, resource)
http://127.0.0.1:8000/eden/vts/presence
Joined Resources: Model
models/vts.py
table = db.define_table(tablename,
Field("vehicle_id", db.vts_vehicle),
location_id,
)
table.vehicle_id.requires = IS_ONE_OF(db,
"vts_vehicle.id",
"vts_vehicle.registration")
Joined Resources: Model
models/vts.py
table = db.define_table(tablename,
Field("vehicle_id", db.vts_vehicle),
location_id,
Field("timestmp", "datetime"),
)
table.vehicle_id.requires = IS_ONE_OF(db, "vts_vehicle.id", "vts_vehicle.registration")
table.timestmp.requires = IS_DATETIME()
Represent
table.vehicle_id.represent = lambda id: function
DAL: Optimised SQL queries
“Find the vehicle with this ID”:
db(db.vts_vehicle.id == id).select()
db(db.vts_vehicle.id == id).select().first()
“Return the Registration”:
db(db.vts_vehicle.id == id).select().first().registration
db(db.vts_vehicle.id == id).\
select(limitby=(0,1)).first().registration
db(db.vts_vehicle.id == id).\
select(db.vts_vehicle.registration,
limitby=(0,1)).first().registration
JR: Represent models/vts.py
table.vehicle_id.represent = lambda id: db(db.vts_vehicle.id == id).\ select(db.vts_vehicle.registration, limitby=(0,1)).first().registration
Components models/vts.py
# Presence as component of vehicle
s3xrc.model.add_component(module,
resource,
multiple=True,
joinby=dict(vts_vehicle="vehicle_id"),
deletable=True,
editable=True)
http://127.0.0.1:8000/eden/vts/vehicle/1/presence
RHeader controllers/vts.pydef shn_vts_rheader(r, tabs=[]):
if r.representation == "html":
rheader_tabs = shn_rheader_tabs(r, tabs)
vehicle = r.record
rheader = DIV(TABLE(
TR(TH(T("Vehicle: ")), vehicle.registration)
),
rheader_tabs
)
return rheader
return None
RHeader Tabs controllers/vts.pydef vehicle():
…
output = shn_rest_controller(module, "vehicle",
rheader=lambda r: shn_vts_rheader(r,
tabs = [(T("Basic Details"), None),
(T("Presence"), "presence")
]))
return output
http://127.0.0.1:8000/eden/vts/vehicle/1/presence
RHeader Tabs
End