web2py:web development like a boss

95
Web2py: Web development like a boss Francisco Gama Tabanez Ribeiro Sunday, December 11, 11

Upload: francisco-ribeiro

Post on 09-May-2015

29.512 views

Category:

Technology


2 download

DESCRIPTION

This presentation shall address the web2py web framework, my favorite way to develop web apps. web2py is a free, open-source web framework for agile development of secure database-driven web applications; it is written in Python and programmable in Python. web2py is a full-stack framework, meaning that it contains all the components you need to build fully functional web applications.Ease of use is the primary goal for web2py. For us, this means reducing the learning and deployment time. This is why web2py is a full-stack framework without dependencies. It requires no installation and has no configuration files. Everything works out of the box, including a web server, database and a web-based IDE that gives access to all the main features. I will show you why web2py can make you more productive by bringing the result of a reflection over the best ideas of the most popular MVC based web frameworks enforcing the best practices for a fast, scalable and secure web application with minimal effort. There will be a live demo where you can get a faster grasp on how does it work and how fun it can be.For more: www.web2py.com

TRANSCRIPT

Page 1: web2py:Web development like a boss

Web2py: Web development like a boss

Francisco Gama Tabanez Ribeiro

Sunday, December 11, 11

Page 2: web2py:Web development like a boss

Agenda

‣ my path on web dev - lessons learned

‣ web2py web framework:

‣ intro

‣ internals

‣ live demo - building a WiKi

‣ resources

Sunday, December 11, 11

Page 3: web2py:Web development like a boss

view source

Sunday, December 11, 11

Page 4: web2py:Web development like a boss

Sunday, December 11, 11

Page 5: web2py:Web development like a boss

Sunday, December 11, 11

Page 6: web2py:Web development like a boss

Sunday, December 11, 11

Page 7: web2py:Web development like a boss

1999 - Lisbon, Portugal

Sunday, December 11, 11

Page 8: web2py:Web development like a boss

Sunday, December 11, 11

Page 9: web2py:Web development like a boss

Sunday, December 11, 11

Page 10: web2py:Web development like a boss

10 1 11 01

010 0

1

Sunday, December 11, 11

Page 11: web2py:Web development like a boss

5 years later...Sunday, December 11, 11

Page 13: web2py:Web development like a boss

Perl?

• LUKE: Is Perl better than Python?

• YODA: No... no... no. Quicker, easier, more seductive.

• LUKE: But how will I know why Python is better than Perl?

• YODA: You will know. . .

When your code you try to read six months from now.

Sunday, December 11, 11

Page 14: web2py:Web development like a boss

Ruby?

Beautiful is better than ugly.

[...]

Although practicality beats purity.

from The Zen of Python

Sunday, December 11, 11

Page 15: web2py:Web development like a boss

God will love you anyway

Heroku

Rubinius

Sunday, December 11, 11

Page 16: web2py:Web development like a boss

Sunday, December 11, 11

Page 17: web2py:Web development like a boss

Sunday, December 11, 11

Page 18: web2py:Web development like a boss

?

Sunday, December 11, 11

Page 19: web2py:Web development like a boss

?

Sunday, December 11, 11

Page 20: web2py:Web development like a boss

lessons learned (1/2)

• rapid turnaround

• secure by design

• web development is mostly about visual UI’s

• relies mostly on user interaction & feedback

• convention over configuration

• flexible as in hackable

Sunday, December 11, 11

Page 21: web2py:Web development like a boss

lessons learned (2/2)

• fast and efficient but mostly scalable and stable

• different things come in different places

• plays well with others

• backward compatibility assured

• live community & support resources

• fun

Sunday, December 11, 11

Page 22: web2py:Web development like a boss

Sunday, December 11, 11

Page 23: web2py:Web development like a boss

Welcome to the club!

founder: Massimo Di Pierro

main contributors: +80

users: +2000

Sunday, December 11, 11

Page 24: web2py:Web development like a boss

Install and run...

Sunday, December 11, 11

Page 25: web2py:Web development like a boss

Install and run...

curl -O http://www.web2py.com/examples/static/web2py_src.zip

Sunday, December 11, 11

Page 26: web2py:Web development like a boss

why?• easy to run, install and play with

• python based

• web IDE included

• web based database admin

• no dependencies, no configuration required

• multiple platform (GAE, EC2, Jython...)

Sunday, December 11, 11

Page 27: web2py:Web development like a boss

why?

• Open source (LGPLv3 license)

• web2py applications have no license constraints

• web2py allows application bytecode compilation

• always backward compatible

• deployment-friendly...

Sunday, December 11, 11

Page 28: web2py:Web development like a boss

deployment..• always backward

compatible

• integrates well with web servers (cgi, fcgi, mod_python, mod_wsgi)

• error logging and ticketing support

• Database Abstraction Layer integrated

• integrated versioning

• integrated self-update capability

• multiple caching methods

• testing methods and debug shell

Sunday, December 11, 11

Page 29: web2py:Web development like a boss

what else?• secure (against XSS, Injection flaws, RFI)

• SSL and multiple authentication methods

• enforces good Software Engineering practices (MVC, Server-side form validation, postbacks...)

• Internationalization support

• HTML/XML, RSS/ATOM, RTF, PDF, JSON, AJAX (includes jQuery), XML-RPC, CSV, REST, WIKI, Flash/AMF, and Linked Data (RDF)

Sunday, December 11, 11

Page 30: web2py:Web development like a boss

Web basedAdmin Interface

Sunday, December 11, 11

Page 31: web2py:Web development like a boss

Hello World

def  hello1():                return  "Hello  World"

controllers/simple_examples.py

Sunday, December 11, 11

Page 32: web2py:Web development like a boss

Olá Mundo(Translation)

def  hello2():                return  T("Hello  World")

controllers/simple_examples.py

Sunday, December 11, 11

Page 33: web2py:Web development like a boss

Controller-View

def  hello3():                return  dict(message=T("Hello  World"))

{{extend  'layout.html'}}<h1>{{=message}}</h1>

controllers/simple_examples.py

views/hello3.html

Sunday, December 11, 11

Page 34: web2py:Web development like a boss

View

{{extend  'layout.html'}}<h1>{{=message}}</h1>

<html>    <head>        <title>example</title>          </head>    <body>          {{include}}      </body>  </html>

views/layout.html

views/hello3.html

Sunday, December 11, 11

Page 35: web2py:Web development like a boss

Web2py: flow

Sunday, December 11, 11

Page 36: web2py:Web development like a boss

Web2py: inside

Sunday, December 11, 11

Page 37: web2py:Web development like a boss

Web2py: inside

Python

Sunday, December 11, 11

Page 38: web2py:Web development like a boss

Web2py: inside

Python

rocket(SSL enabled web server)

API for third party servers(Apache,...)

Sunday, December 11, 11

Page 39: web2py:Web development like a boss

Web2py: inside

Python

rocket(SSL enabled web server)

API for third party servers(Apache,...)

Core libraries(HTTP request/response, session,

auth, services, DAL,...)

Contrib(simplejson, markdown, memcache, pyrtf, rss,...)

Sunday, December 11, 11

Page 40: web2py:Web development like a boss

Web2py: inside

Python

rocket(SSL enabled web server)

API for third party servers(Apache,...)

Core libraries(HTTP request/response, session,

auth, services, DAL,...)

User Applications

admin welcome user app

Contrib(simplejson, markdown, memcache, pyrtf, rss,...)

examples

Sunday, December 11, 11

Page 41: web2py:Web development like a boss

Web2py: inside

Python

rocket(SSL enabled web server)

API for third party servers(Apache,...)

Core libraries(HTTP request/response, session,

auth, services, DAL,...)

User Applications

admin welcome user app

Contrib(simplejson, markdown, memcache, pyrtf, rss,...)

examples

Sunday, December 11, 11

Page 42: web2py:Web development like a boss

web2py app inside

Sunday, December 11, 11

Page 43: web2py:Web development like a boss

web2py app inside

models

controllers

views

translations

static data

plugins & modules

appadmin

data

Sunday, December 11, 11

Page 44: web2py:Web development like a boss

web2py app inside

models

controllers

views

translations

static data

plugins & modules

appadmin

data

Sunday, December 11, 11

Page 45: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

web2py app inside

Sunday, December 11, 11

Page 46: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

db = SQLDB(‘sqlite://data.db’)

db.define_table(‘category’,Field(‘name’))

db.define_table(‘recipe’,Field(‘title’),Field(‘category’,db.category),Field(‘description’,‘text’))

web2py app inside

Sunday, December 11, 11

Page 47: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

db = SQLDB(‘sqlite://data.db’)

db.define_table(‘category’,Field(‘name’))

db.define_table(‘recipe’,Field(‘title’),Field(‘category’,db.category),Field(‘description’,‘text’))

SQlite

MySQL

PostgreSQL

Oracle

MSSQL

DB2

Firebird

MyBase

Informix

Google App Engine

Database types:

web2py app inside

Sunday, December 11, 11

Page 48: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

db = SQLDB(‘sqlite://data.db’)

db.define_table(‘category’,Field(‘name’))

db.define_table(‘recipe’,Field(‘title’),Field(‘category’,db.category),Field(‘description’,‘text’))

web2py app inside

Sunday, December 11, 11

Page 49: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

db = SQLDB(‘sqlite://data.db’)

db.define_table(‘category’,Field(‘name’))

db.define_table(‘recipe’,Field(‘title’),Field(‘category’,db.category),Field(‘description’,‘text’))

string

textinteger

double

datedatetime

time

booleanpassword

upload

blob

referencelist:string

list:interger

list:reference

Field types:

web2py app inside

Sunday, December 11, 11

Page 50: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

db = SQLDB(‘sqlite://data.db’)

db.define_table(‘category’,Field(‘name’))

db.define_table(‘recipe’,Field(‘title’),Field(‘category’,db.category),Field(‘description’,‘text’))

web2py app inside

Sunday, December 11, 11

Page 51: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

db = SQLDB(‘sqlite://data.db’)

db.define_table(‘category’,Field(‘name’))

db.define_table(‘recipe’,Field(‘title’),Field(‘category’,db.category),Field(‘description’,‘text’))

db.recipe.title.requires=IS_NOT_EMPTY()db.recipe.category.requires=IS_IN_DB(db,'category.id','category.name')db.category.name.requires=IS_NOT_IN_DB(db,'category.name')db.recipe.description.default='Fill your recipe in here...'

web2py app inside

Sunday, December 11, 11

Page 52: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

db = SQLDB(‘sqlite://data.db’)

db.define_table(‘category’,Field(‘name’))

db.define_table(‘recipe’,Field(‘title’),Field(‘category’,db.category),Field(‘description’,‘text’))

db.recipe.title.requires=IS_NOT_EMPTY()db.recipe.category.requires=IS_IN_DB(db,'category.id','category.name')db.category.name.requires=IS_NOT_IN_DB(db,'category.name')db.recipe.description.default='Fill your recipe in here...'

IS_DATEIS_DATETIME

IS_DATETIME_IN_RANGEIS_DATE_IN_RANGE

IS_DECIMAL_IN_RANGEIS_EMAIL

IS_EMPTY_ORIS_EQUAL_TO

IS_EXPRIS_FLOAT_IN_RANGE

IS_GENERIC_URLIS_HTTP_URL

IS_IMAGEIS_INT_IN_RANGE

IS_IN_DBIS_IN_SET

IS_IN_SUBSETIS_IPV4

IS_LENGTHIS_LIST_OFIS_LOWERIS_MATCH

IS_NOT_EMPTYIS_NOT_IN_DBIS_NULL_OR

IS_SLUGIS_STRONG

IS_TIMEIS_UPLOAD_FILENAME

IS_UPPERIS_URL

IS_ALPHANUMERIC

Validators:

web2py app inside

Sunday, December 11, 11

Page 53: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

web2py app inside

Sunday, December 11, 11

Page 54: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

def index(): return dict(recipes=db().select(db.recipe.ALL))

def add(): form=SQLFORM(db.recipe) if form.accepts(request.vars): redirect(URL(r=request,f='index')) return dict(form=form)

def show():recipes=db(db.recipe.id==request.args[0]).select()if not len(recipes):

redirect(URL(r=request,f='index')) return dict(recipe=recipes[0])

web2py app inside

Sunday, December 11, 11

Page 55: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

in file views/default/add.html:{{extend 'layout.html'}}<h1>{{T(‘New recipe’)}}</h1>{{=form}}

in file views/default/index.html:{{extend 'layout.html'}}<h1> {{T(‘List all recipes’)}} </h1><table>{{for recipe in recipes:}}<tr><td>{{=A(T(recipe.title),_href=URL(r=request,f='show', args=recipe.id))}}</td></tr>{{pass}}</table>

in file views/default/show.html:{{extend 'layout.html'}}<h1> {{=T(recipe.title)}} {{=db.recipe.category.represent(recipe.category)}}</h1><pre> {{=recipe.description}}</pre>

web2py app inside

Sunday, December 11, 11

Page 56: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

T(‘New recipe’)

T(‘List all recipes’)

T(recipe.title)

‘Nova receita’‘Nouvelle receité’...

‘Listar receitas’‘Lister receité’...

‘bitoque’‘duple cliché’...

web2py app inside

Sunday, December 11, 11

Page 57: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

images

css

js

web2py app inside

Sunday, December 11, 11

Page 58: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

ways to extend your apps:• modules are good way to import external code• plugins are applications subsets - a small application “inside” your application

web2py app inside

Sunday, December 11, 11

Page 59: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

data

web2py app inside

• databases (SQlite, MySQL, PostgreSQL, Oracle, MSSQL, DB2, Firebird, MyBase, Informix, Google App Engine)

• metadata for automatic migrations

• cache

Sunday, December 11, 11

Page 60: web2py:Web development like a boss

models

controllers

views

translations

static data

plugins & modules

appadmin

datadefault web based interface to your data

web2py app inside

Sunday, December 11, 11

Page 61: web2py:Web development like a boss

web2py URL parsinghttp://www.myhost.com:8000/myapp/default/index.html/a/b/c?name=Max

request.application = “myapp”request.controller = “default”

request.function = “index”request.extension = “html”

request.args = [‘a’,’b’,’c’]request.vars.name = “Max”

Environment variablesare in request.env

equivalent torequest.vars[‘name’]

Sunday, December 11, 11

Page 62: web2py:Web development like a boss

• functions in controllers return dicts() into views

• controller methods are exposed to views with the same name which is also used in the URL

• input validators (forms) are defined in the model as integrity constraints (requires)

• DAL automatically creates the id field in your tables

• model code has full application scope

remember..

Sunday, December 11, 11

Page 63: web2py:Web development like a boss

remember..• you can use your editor of choice

• you can use DAL separately

• in controller functions you can redefine the target view with response.view=”theme/myview.html”  

• web2py shell is your friend

• recommended - start your files with: #  coding:  utf8

Sunday, December 11, 11

Page 64: web2py:Web development like a boss

sessions

<html>      <head></head>      <body>            <h1>{{=message}}</h1>            <h2>Number  of  visits:  {{=counter}}</h2>      </body></html>

def  index():        session.counter  =  (session.counter  or  0)  +  1        return  dict(message="Hello  from  MyApp",  counter=session.counter)

inside controller:

inside view:

Sunday, December 11, 11

Page 65: web2py:Web development like a boss

Overview

Sunday, December 11, 11

Page 66: web2py:Web development like a boss

DAL select()

db(query).select(    field1,  field2,  ...,    left=[db.table.on(query)],    orderby=field|~field,    groupby=field|field    limitby=(0,10),    cache=(cache.ram,5000))

Examples:rows = db(db.recipe).select()

rows = db(db.recipe.id>0).select(db.recipe.title, db.recipe.category,orderby = db.recipe.category, distinct=True)

# christmas recipes from 2000query1 = db.recipe.created_in.year()>2000query2 = db.recipe_created_in.month()<10rows = db(query1 & query2).select()

Sunday, December 11, 11

Page 67: web2py:Web development like a boss

DAL select()

db(query).select(    field1,  field2,  ...,    left=[db.table.on(query)],    orderby=field|~field,    groupby=field|field    limitby=(0,10),    cache=(cache.ram,5000))

Examples:rows = db(db.recipe).select()

rows = db(db.recipe.id>0).select(db.recipe.title, db.recipe.category,orderby = db.recipe.category, distinct=True)

# christmas recipes from 2000query1 = db.recipe.created_in.year()>2000query2 = db.recipe_created_in.month()<10rows = db(query1 & query2).select()

equivalent to: rows = db(db.recipe.id>0).select(db.recipe.ALL)

Sunday, December 11, 11

Page 68: web2py:Web development like a boss

DAL select()

db(query).select(    field1,  field2,  ...,    left=[db.table.on(query)],    orderby=field|~field,    groupby=field|field    limitby=(0,10),    cache=(cache.ram,5000))

Examples:rows = db(db.recipe).select()

rows = db(db.recipe.id>0).select(db.recipe.title, db.recipe.category,orderby = db.recipe.category, distinct=True)

# christmas recipes from 2000query1 = db.recipe.created_in.year()>2000query2 = db.recipe_created_in.month()<10rows = db(query1 & query2).select()

equivalent to: rows = db(db.recipe.id>0).select(db.recipe.ALL)

queries can be combined with and(&), or(|) and not(~)

Sunday, December 11, 11

Page 69: web2py:Web development like a boss

DAL operations• Insert:

db.category.insert(name=‘soup’)

• Update:db(db.category.name==‘soup’).update(name=‘french soups’)

• Delete:db(db.category.name==‘french soups’).delete()

• Count:db(db.category.name.like(‘%soup%’)).count()

Sunday, December 11, 11

Page 70: web2py:Web development like a boss

DAL operations• Insert:

db.category.insert(name=‘soup’)

• Update:db(db.category.name==‘soup’).update(name=‘french soups’)

• Delete:db(db.category.name==‘french soups’).delete()

• Count:db(db.category.name.like(‘%soup%’)).count()

Other operators:.max(), .min(), .sum(), .belongs(), .like(),...

Sunday, December 11, 11

Page 71: web2py:Web development like a boss

DAL operations• Insert:

db.category.insert(name=‘soup’)

• Update:db(db.category.name==‘soup’).update(name=‘french soups’)

• Delete:db(db.category.name==‘french soups’).delete()

• Count:db(db.category.name.like(‘%soup%’)).count()

Other operations:transactions, inner joins, left outer joins, nested selects, self-references, many2many, ...

Other operators:.max(), .min(), .sum(), .belongs(), .like(),...

Sunday, December 11, 11

Page 72: web2py:Web development like a boss

Forms

• SQLFORM() / SQLFORM.factory()

• FORM()

• CRUD()

• <form></form>

Sunday, December 11, 11

Page 74: web2py:Web development like a boss

ComponentsLOAD()

{{=LOAD(‘controller’,‘function’,  ajax=True)}}

Sunday, December 11, 11

Page 75: web2py:Web development like a boss

ComponentsLOAD()

{{=LOAD(‘controller’,‘function’,  ajax=True)}}

supports auth signatures

Sunday, December 11, 11

Page 76: web2py:Web development like a boss

web2py Shell

python web2py.py -S myapplication -M

Sunday, December 11, 11

Page 77: web2py:Web development like a boss

HTML helpers

• BEAUTIFY(whatever)

• URL('application', 'controller', 'function', args=['x', 'y'], vars=dict(z='t'))

• much more... /application/controller/function/x/y?z=t

Sunday, December 11, 11

Page 78: web2py:Web development like a boss

Authentication & Authorization (Role-based)

Sunday, December 11, 11

Page 79: web2py:Web development like a boss

Authentication & Authorization (Role-based)doc_id  =  db.document.insert(body  =  'top  secret')  

agents  =  auth.add_group(role  =  'Secret  Agent')  

auth.add_membership(agents,  james_bond)

auth.add_permission(agents,  'read',  secrets)

auth.has_permission('read',  secrets,  doc_id,  james_bond)

auth.has_permission('update',  secrets,  doc_id,  james_bond)

auth.is_logged_in()

Sunday, December 11, 11

Page 80: web2py:Web development like a boss

Authentication & Authorization (Role-based)

@auth.requires_login()

@auth.requires_membership(agents)

@auth.requires_permission('read',  secrets)

@auth.requires_permission('delete',  'any  file')

@auth.requires(auth.user_id==1  or  request.client=='127.0.0.1')

@auth.requires_permission('add',  'number')

you also have:  agents  =  auth.add_group(role  =  'Secret  Agent')    auth.add_membership(agents,  james_bond)  auth.add_permission(agents,  'read',  secrets)

Sunday, December 11, 11

Page 81: web2py:Web development like a boss

@[email protected]@service.xmldef list_recipes(): return db(db.recipe).select()

@[email protected]@[email protected]@[email protected]@[email protected]@service.amfrpc3('domain')

Services

http://myhost/application/controller/list_recipes.xml

Sunday, December 11, 11

Page 82: web2py:Web development like a boss

@[email protected]@service.xmldef list_recipes(): return db(db.recipe).select()

@[email protected]@[email protected]@[email protected]@[email protected]@service.amfrpc3('domain')

Services

http://myhost/application/controller/list_recipes.xml.csv

....json

Sunday, December 11, 11

Page 83: web2py:Web development like a boss

@[email protected]@service.xmldef list_recipes(): return db(db.recipe).select()

@[email protected]@[email protected]@[email protected]@[email protected]@service.amfrpc3('domain')

Services

http://myhost/application/controller/list_recipes.xml.csv

....json

Sunday, December 11, 11

Page 84: web2py:Web development like a boss

Errors (ticketing)

errors/exceptions are logged into tickets

Sunday, December 11, 11

Page 85: web2py:Web development like a boss

Other

• Cron

• Routes

• Plugins

• Modules

• Grids

Caching in functions:  @cache("key",cache.ram,5000)  def  f():  return  dict()

Caching actions/views:  @cache(request.env.path_info,5000,cache.ram)  def  action():                    return  response.render(response.view,dict())

could be:cache.ram, cache.disk, cache.memcache

Sunday, December 11, 11

Page 86: web2py:Web development like a boss

demoWiki

Sunday, December 11, 11

Page 87: web2py:Web development like a boss

demoWiKi app(features)

• add pages

• show pages

• edit pages

• versioning

• authentication (local and remote)

• internationalization

• comments (with/without AJAX)

Sunday, December 11, 11

Page 88: web2py:Web development like a boss

demoWiKi app(model)

Sunday, December 11, 11

Page 89: web2py:Web development like a boss

web2py in real life

Francisco Costa

Sunday, December 11, 11

Page 90: web2py:Web development like a boss

Documentation (1/2)

• online book (www.web2py.com/book)

• book (printed version - amzn.to/vzjiqT)

• screencasts (www.vimeo.com)

• interactive examples (default app)

• AlterEgo (FAQ - www.web2py.com/AlterEgo)

Sunday, December 11, 11

Page 91: web2py:Web development like a boss

Documentation (2/2)

• epydoc (www.web2py.com/examples/static/epydoc/)

• API:(www.web2py.com/book/default/chapter/04#API)

Sunday, December 11, 11

Page 92: web2py:Web development like a boss

Community (1/2)

• free web2py appliances (www.web2py.com/appliances)

• code snippets (www.web2pyslices.com)

• groups:• users - http://groups.google.com/group/web2py/

• developers - http://groups.google.com/group/web2py-developers

Sunday, December 11, 11

Page 93: web2py:Web development like a boss

Community (2/2)

• #web2py (IRC channel at irc.freenode.net)

• twitter (http://twitter.com/web2py)

• user voice (http://web2py.uservoice.com)

• web2py websites (www.web2py.com/poweredby)

• web2py plugins (www.web2py.com/plugins/)

Sunday, December 11, 11

Page 94: web2py:Web development like a boss

Thank you

childish wont-let-go nickname: blackthorne

blackthorne (geek) bthorne_daily (social)

[email protected] (PGP key: 0xBDD20CF1)

http://www.digitalloft.org (homepage)

Sunday, December 11, 11

Page 95: web2py:Web development like a boss

web2py app defaults• menu

• web2py_ajax (jQuery)

• auth, mail, download and services

• english default lang translation

• generic view

Sunday, December 11, 11