GHC Participant Training
description
Transcript of GHC Participant Training
Sahana Eden:Emergency
Development Environment
30 September 2010, Grace Hopper Celebration
Fran Boon
Agenda
• Stack Overview
• Getting Set up
• Model View Controller– Filesystem Layout
• Build a New Module– S3 REST Controller
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
• Organisation Registry: org
• Person Finder: pr, mpr, dvi
• Request Management: rms
• Inventory: inv
• Shelter Registry: cr
• Mapping: gis
• Messaging: msg
LaunchPad
Merge proposal
Branches
Trunk
Local Branch
Your Branch
bzr merge
bzr push
Request processing
1. Web2Py environment setup
2. All Models executed (alphabetical order)
3. Controller executed
4. Controller Function executed
5. View parsed (explicit variable passing)
6. HTML/JS returned to browser
Emergency• We have to build a module before bed!
Software Development Cycle
Incident Reporting SystemData:• Location• Date• Reporter• Details
Screens:• Report Incident• View Incidents• Update Incident
Define Data
models/inc.py
table = db.define_table("inc_incident",
location_id(),
Field("date", "date"),
person_id(),
comments()
)
Forms for CRUD
controllers/inc.py
def incident():
return shn_rest_controller("inc",
"incident")
We’re done!
http://127.0.0.1:8000/eden/inc/incident
1.Create an incident.
2.View in different formats:– .json, .xml, .xls, .pdf
http://127.0.0.1:8000/eden/inc/incident/1.json
Views: Custom REST
views/inc/incident_list_create.html
{{extend "layout.html"}}
<p>A Normal HTML Paragraph</p>
{{rheader="A Paragraph inserted inside the page"}}
{{include "_list_create.html"}}
{{include "gis/location_autocomplete.js"}}
•Python code inside {{ }} is parsed server-side•Views can extend (one) & include (many) other views•Extend ‘layout’ for overall look/feel•Variables only visible to views if:
– explicitly passed in return dict()– stored in global variables: request, response, session
SQL constraints / Validators
models/inc.py
table = db.define_table("inc_incident",
Field("code", unique=True),
…
)
DAL supports Live Migrations
Field Types models/inc.py
table = db.define_table ("inc_incident",
…
Field("date", "date"),
…
)
Default Values
models/inc.py
table = db.define_table("inc_incident",
…
Field("date_date", "date", default=request.utcnow),
…
)
Labels models/inc.py
table.person_id.label = "Reporter"
Internationalisation models/inc.py
table.person_id.label = T("Reporter“)
Comments models/inc.py
table.code.comment = SPAN("*", _class="req")
Requires
models/03_gis.py
db.gis_location.comment = …
db.gis_location.requires = IS_ONE_OF(…)
Represent
models/03_gis.py
db.gis_location.represent = shn_location_represent
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.
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()
End
Enable Module models/000_config.py
deployment_settings.modules = Storage(
…
#irs = Storage(
inc = Storage(
name_nice = "Incident Reporting System", description = "Report Incidents",
module_type = 3
),
…
)
Index page controllers/inc.py
module = request.controller
def index():
"Custom View"
module_name = \ deployment_settings.modules[module].name_nice
return dict(module_name=module_name)
View
views/inc/index.html
{{extend "layout.html"}}
{{=H2(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/inc.py
response.menu_options = [
[T("Incidents"), False, URL(r=request, f="incident"),[[T("List"), False, URL(r=request, f="incident")],[T("Add"), False, URL(r=request, f="incident",
args="create")] ]]]
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
S3 is built on Web2Py
REST
CRUD
SQLFORM
FORM
Form submission
• Use Firebug’s Net Panel to look at a form submission.
• Each field has an entry in form.vars
• Can add additional vars to the form in a custom View
• Can process these within our Controller– onvalidation: Before DB I/O– onaccept: After DB I/O
Documentation
• Examples from other modules
• Developer Guidelines on Wiki:http://eden.sahanafoundation.org/wiki/DeveloperGuidelines
• But the best…?
Use the Source, Luke!Many resources and tricks on the Internet find you will, but the ultimate answers only in the source lie