• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
web2py:Web development like a boss
 

web2py:Web development like a boss

on

  • 21,420 views

This presentation shall address the web2py web framework, my favorite way to develop web apps. ...

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

Statistics

Views

Total Views
21,420
Views on SlideShare
21,408
Embed Views
12

Actions

Likes
7
Downloads
171
Comments
0

1 Embed 12

http://127.0.0.1 12

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

web2py:Web development like a boss web2py:Web development like a boss Presentation Transcript

  • Web2py: Web development like a boss Francisco Gama Tabanez RibeiroSunday, December 11, 11
  • Agenda ‣ my path on web dev - lessons learned ‣ web2py web framework: ‣ intro ‣ internals ‣ live demo - building a WiKi ‣ resourcesSunday, December 11, 11
  • view sourceSunday, December 11, 11
  • Sunday, December 11, 11
  • Sunday, December 11, 11
  • Sunday, December 11, 11
  • 1999 - Lisbon, PortugalSunday, December 11, 11
  • Sunday, December 11, 11
  • Sunday, December 11, 11
  • 1 0 0 0 1 11 0 1 1 01Sunday, December 11, 11
  • 5 years later...Sunday, December 11, 11
  • PHP? Python is well designed, PHP is not: Although it’s perfectly possible to write good code in PHP, it’s much easier to write great code in Python from Why PHP Is Fun and Easy But Python Is Marriage MaterialSunday, December 11, 11
  • 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
  • Ruby? Beautiful is better than ugly. [...] Although practicality beats purity. from The Zen of PythonSunday, December 11, 11
  • God will love you anyway Rubinius HerokuSunday, December 11, 11
  • Sunday, December 11, 11
  • Sunday, December 11, 11
  • ?Sunday, December 11, 11
  • ?Sunday, December 11, 11
  • 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 hackableSunday, December 11, 11
  • 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 • funSunday, December 11, 11
  • Sunday, December 11, 11
  • Welcome to the club! founder: Massimo Di Pierro main contributors: +80 users: +2000Sunday, December 11, 11
  • Install and run...Sunday, December 11, 11
  • Install and run... curl -O http://www.web2py.com/examples/static/web2py_src.zipSunday, December 11, 11
  • 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
  • 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
  • deployment.. • always backward compatible • integrated versioning • integrates well with web • integrated self-update servers (cgi, fcgi, capability mod_python, mod_wsgi) • multiple caching methods • error logging and ticketing support • testing methods and debug shell • Database Abstraction Layer integratedSunday, December 11, 11
  • 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
  • Web based Admin InterfaceSunday, December 11, 11
  • Hello World controllers/simple_examples.py def  hello1():                return  "Hello  World"Sunday, December 11, 11
  • Olá Mundo (Translation) controllers/simple_examples.py def  hello2():                return  T("Hello  World")Sunday, December 11, 11
  • Controller-View controllers/simple_examples.py def  hello3():                return  dict(message=T("Hello  World")) views/hello3.html {{extend  layout.html}} <h1>{{=message}}</h1>Sunday, December 11, 11
  • views/layout.html View <html>    <head>        <title>example</title>          </head>    <body>          {{include}}      </body>  </html> views/hello3.html {{extend  layout.html}} <h1>{{=message}}</h1>Sunday, December 11, 11
  • Web2py: flowSunday, December 11, 11
  • Web2py: insideSunday, December 11, 11
  • Web2py: inside PythonSunday, December 11, 11
  • Web2py: inside rocket API for third party servers (SSL enabled web server) (Apache,...) PythonSunday, December 11, 11
  • Web2py: inside Core libraries Contrib (HTTP request/response, session, (simplejson, markdown, auth, services, DAL,...) memcache, pyrtf, rss,...) rocket API for third party servers (SSL enabled web server) (Apache,...) PythonSunday, December 11, 11
  • Web2py: inside User Applications admin welcome examples user app Core libraries Contrib (HTTP request/response, session, (simplejson, markdown, auth, services, DAL,...) memcache, pyrtf, rss,...) rocket API for third party servers (SSL enabled web server) (Apache,...) PythonSunday, December 11, 11
  • Web2py: inside User Applications admin welcome examples user app Core libraries Contrib (HTTP request/response, session, (simplejson, markdown, auth, services, DAL,...) memcache, pyrtf, rss,...) rocket API for third party servers (SSL enabled web server) (Apache,...) PythonSunday, December 11, 11
  • web2py app insideSunday, December 11, 11
  • web2py app inside models controllers views translations static data plugins & modules data appadminSunday, December 11, 11
  • web2py app inside models controllers views translations static data plugins & modules data appadminSunday, December 11, 11
  • web2py app inside models controllers views translations static data plugins & modules data appadminSunday, December 11, 11
  • web2py app inside db = SQLDB(‘sqlite://data.db’) models db.define_table(‘category’, controllers Field(‘name’)) views db.define_table(‘recipe’, translations Field(‘title’), Field(‘category’,db.category), static data Field(‘description’,‘text’)) plugins & modules data appadminSunday, December 11, 11
  • web2py app inside db = SQLDB(‘sqlite://data.db’) models db.define_table(‘category’, Database types: controllers Field(‘name’)) SQlite views MySQL db.define_table(‘recipe’, PostgreSQL translations Field(‘title’), Oracle Field(‘category’,db.category), static data MSSQLField(‘description’,‘text’)) DB2 plugins & modules Firebird data MyBase Informix appadmin Google App EngineSunday, December 11, 11
  • web2py app inside db = SQLDB(‘sqlite://data.db’) models db.define_table(‘category’, controllers Field(‘name’)) views db.define_table(‘recipe’, translations Field(‘title’), Field(‘category’,db.category), static data Field(‘description’,‘text’)) plugins & modules data appadminSunday, December 11, 11
  • web2py app inside Field types: db = SQLDB(‘sqlite://data.db’) string models text integer db.define_table(‘category’, controllers double Field(‘name’)) date views db.define_table(‘recipe’, datetime time translations Field(‘title’), boolean Field(‘category’,db.category), password static data Field(‘description’,‘text’)) upload plugins & modules blob reference data list:string list:interger appadmin list:referenceSunday, December 11, 11
  • web2py app inside db = SQLDB(‘sqlite://data.db’) models db.define_table(‘category’, controllers Field(‘name’)) views db.define_table(‘recipe’, translations Field(‘title’), Field(‘category’,db.category), static data Field(‘description’,‘text’)) plugins & modules data appadminSunday, December 11, 11
  • web2py app inside db = SQLDB(‘sqlite://data.db’) models db.define_table(‘category’, controllers Field(‘name’)) views db.define_table(‘recipe’, translations Field(‘title’), Field(‘category’,db.category), static data Field(‘description’,‘text’)) plugins & modules db.recipe.title.requires=IS_NOT_EMPTY() data db.recipe.category.requires=IS_IN_DB(db,category.id,category.name) db.category.name.requires=IS_NOT_IN_DB(db,category.name) appadmin db.recipe.description.default=Fill your recipe in here...Sunday, December 11, 11
  • web2py app inside db = SQLDB(‘sqlite://data.db’) models db.define_table(‘category’, Validators: controllers Field(‘name’)) IS_IN_SUBSET IS_DATE IS_IPV4 views IS_DATETIME db.define_table(‘recipe’, IS_LENGTH IS_DATETIME_IN_RANGE IS_LIST_OF IS_LOWER IS_DATE_IN_RANGE translations Field(‘title’), IS_DECIMAL_IN_RANGE IS_MATCH IS_EMAIL Field(‘category’,db.category), IS_NOT_EMPTY IS_EMPTY_OR static data IS_NOT_IN_DB IS_EQUAL_TO Field(‘description’,‘text’)) IS_NULL_OR IS_EXPR IS_SLUG IS_FLOAT_IN_RANGE plugins & modules IS_STRONG IS_GENERIC_URL IS_TIME IS_HTTP_URL db.recipe.title.requires=IS_NOT_EMPTY() IS_UPLOAD_FILENAME IS_UPPER data IS_IMAGE db.recipe.category.requires=IS_IN_DB(db,category.id,category.name) IS_INT_IN_RANGE IS_URL IS_IN_DB db.category.name.requires=IS_NOT_IN_DB(db,category.name) appadmin IS_ALPHANUMERIC IS_IN_SET db.recipe.description.default=Fill your recipe in here...Sunday, December 11, 11
  • web2py app inside models controllers views translations static data plugins & modules data appadminSunday, December 11, 11
  • web2py app inside models def index(): return dict(recipes=db().select(db.recipe.ALL)) controllers def add(): views form=SQLFORM(db.recipe) if form.accepts(request.vars): translations redirect(URL(r=request,f=index)) return dict(form=form) static data def show(): plugins & modules recipes=db(db.recipe.id==request.args[0]).select() if not len(recipes): data redirect(URL(r=request,f=index)) return dict(recipe=recipes[0]) appadminSunday, December 11, 11
  • web2py app inside in file views/default/add.html: {{extend layout.html}} <h1>{{T(‘New recipe’)}}</h1> {{=form}} models in file views/default/index.html: controllers {{extend layout.html}} <h1> {{T(‘List all recipes’)}} </h1> views <table> {{for recipe in recipes:}} translations <tr><td>{{=A(T(recipe.title),_href=URL(r=request,f=sh ow, args=recipe.id))}}</td></tr> static data {{pass}} plugins & modules </table> data in file views/default/show.html: {{extend layout.html}} appadmin <h1> {{=T(recipe.title)}} {{=db.recipe.category.represent(recipe.category)}} </h1> <pre> {{=recipe.description}}</pre>Sunday, December 11, 11
  • web2py app inside models ‘Nova receita’ T(‘New recipe’) ‘Nouvelle receité’ controllers ... views ‘Listar receitas’ translations T(‘List all recipes’) ‘Lister receité’ static data ... plugins & modules ‘bitoque’ data T(recipe.title) ‘duple cliché’ ... appadminSunday, December 11, 11
  • web2py app inside models controllers images views translations css static data plugins & modules data js appadminSunday, December 11, 11
  • web2py app inside models controllers ways to extend your apps: • modules are good way to import external views code translations • plugins are applications subsets - a small application “inside” your application static data plugins & modules data appadminSunday, December 11, 11
  • web2py app inside models controllers views translations • databases (SQlite, MySQL, PostgreSQL, Oracle, MSSQL, DB2, Firebird, MyBase, static data Informix, Google App Engine) plugins & modules • metadata for automatic migrations data • cache appadminSunday, December 11, 11
  • web2py app inside models controllers views translations static data plugins & modules data appadmin default web based interface to your dataSunday, December 11, 11
  • web2py URL parsing http://www.myhost.com:8000/myapp/default/index.html/a/b/c?name=Maxrequest.application = “myapp” request.controller = “default” request.function = “index” request.extension = “html” request.args = [‘a’,’b’,’c’] request.vars.name = “Max” Environment variables equivalent to are in request.env request.vars[‘name’]Sunday, December 11, 11
  • remember.. • 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 scopeSunday, December 11, 11
  • 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:  utf8Sunday, December 11, 11
  • sessions inside controller: def  index():        session.counter  =  (session.counter  or  0)  +  1        return  dict(message="Hello  from  MyApp",  counter=session.counter) inside view: <html>      <head></head>      <body>            <h1>{{=message}}</h1>            <h2>Number  of  visits:  {{=counter}}</h2>      </body> </html>Sunday, December 11, 11
  • OverviewSunday, December 11, 11
  • DAL select() Examples: db(query).select( rows = db(db.recipe).select()    field1,  field2,  ...,    left=[db.table.on(query)], rows = db(db.recipe.id>0).select(    orderby=field|~field, db.recipe.title, db.recipe.category,    groupby=field|field orderby = db.recipe.category,    limitby=(0,10), distinct=True)    cache=(cache.ram,5000)) # christmas recipes from 2000 query1 = db.recipe.created_in.year()>2000 query2 = db.recipe_created_in.month()<10 rows = db(query1 & query2).select()Sunday, December 11, 11
  • DAL select() equivalent to: rows = db(db.recipe.id>0).select(db.recipe.ALL) Examples: db(query).select( rows = db(db.recipe).select()    field1,  field2,  ...,    left=[db.table.on(query)], rows = db(db.recipe.id>0).select(    orderby=field|~field, db.recipe.title, db.recipe.category,    groupby=field|field orderby = db.recipe.category,    limitby=(0,10), distinct=True)    cache=(cache.ram,5000)) # christmas recipes from 2000 query1 = db.recipe.created_in.year()>2000 query2 = db.recipe_created_in.month()<10 rows = db(query1 & query2).select()Sunday, December 11, 11
  • DAL select() equivalent to: rows = db(db.recipe.id>0).select(db.recipe.ALL) Examples: db(query).select( rows = db(db.recipe).select()    field1,  field2,  ...,    left=[db.table.on(query)], rows = db(db.recipe.id>0).select(    orderby=field|~field, db.recipe.title, db.recipe.category,    groupby=field|field orderby = db.recipe.category,    limitby=(0,10), distinct=True)    cache=(cache.ram,5000)) # christmas recipes from 2000 query1 = db.recipe.created_in.year()>2000 query2 = db.recipe_created_in.month()<10 rows = db(query1 & query2).select() queries can be combined with and(&), or(|) and not(~)Sunday, December 11, 11
  • 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
  • DAL operations Other operators: • Insert: .max(), .min(), .sum(), db.category.insert(name=‘soup’) .belongs(), .like(),... • 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
  • DAL operations Other operators: • Insert: .max(), .min(), .sum(), db.category.insert(name=‘soup’) .belongs(), .like(),... • 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, ...Sunday, December 11, 11
  • Forms • SQLFORM() / SQLFORM.factory() • FORM() • CRUD() • <form></form>Sunday, December 11, 11
  • HTML helpers (form) inside controller: def display_form(): form=FORM(Your name:, INPUT(_name=name, requires=IS_NOT_EMPTY()), INPUT(_type=submit)) if form.accepts(request.vars, session): response.flash = form.vars.name +, thank you elif form.errors: response.flash = form has errors else: response.flash = please fill the form return dict(form=form) inside view: ... <div class="flash">{{=response.flash or }}</div> {{=form}} ...Sunday, December 11, 11
  • Components LOAD() {{=LOAD(‘controller’,‘function’,  ajax=True)}}Sunday, December 11, 11
  • Components LOAD() supports auth signatures {{=LOAD(‘controller’,‘function’,  ajax=True)}}Sunday, December 11, 11
  • web2py Shell python web2py.py -S myapplication -MSunday, December 11, 11
  • HTML helpers • BEAUTIFY(whatever) • URL(application, controller, function, args=[x, y], vars=dict(z=t)) • much more... /application/controller/function/x/y?z=tSunday, December 11, 11
  • Authentication & Authorization (Role-based)Sunday, December 11, 11
  • 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
  • Authentication & Authorization (Role-based) @auth.requires_login() you also have:  agents  =  auth.add_group(role  =  Secret  Agent)    auth.add_membership(agents,  james_bond) @auth.requires_membership(agents)  auth.add_permission(agents,  read,  secrets) @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)Sunday, December 11, 11
  • Services @service.run @service.csv @service.csv @service.rss @service.json @service.rss @service.jsonrpc @service.xml @service.xml def list_recipes(): @service.xmlrpc @service.soap return db(db.recipe).select() @service.amfrpc3(domain) http://myhost/application/controller/list_recipes.xmlSunday, December 11, 11
  • Services @service.run @service.csv @service.csv @service.rss @service.json @service.rss @service.jsonrpc @service.xml @service.xml def list_recipes(): @service.xmlrpc @service.soap return db(db.recipe).select() @service.amfrpc3(domain) http://myhost/application/controller/list_recipes.xml .csv .json ...Sunday, December 11, 11
  • Services @service.run @service.csv @service.csv @service.rss @service.json @service.rss @service.jsonrpc @service.xml @service.xml def list_recipes(): @service.xmlrpc @service.soap return db(db.recipe).select() @service.amfrpc3(domain) http://myhost/application/controller/list_recipes.xml .csv .json ...Sunday, December 11, 11
  • Errors (ticketing) errors/exceptions are logged into ticketsSunday, December 11, 11
  • Other could be: cache.ram, cache.disk, cache.memcache • Cron Caching in functions:  @cache("key",cache.ram,5000) • Routes  def  f():  return  dict() Caching actions/views: • Plugins  @cache(request.env.path_info,5000,cache.ram)  def  action():                    return  response.render(response.view,dict()) • Modules • GridsSunday, December 11, 11
  • demoWikiSunday, December 11, 11
  • demoWiKi app (features) • add pages • authentication (local and remote) • show pages • internationalization • edit pages • comments • versioning (with/without AJAX)Sunday, December 11, 11
  • demoWiKi app (model)Sunday, December 11, 11
  • web2py in real life Francisco CostaSunday, December 11, 11
  • 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
  • Documentation (2/2) • epydoc (www.web2py.com/examples/static/epydoc/) • API: (www.web2py.com/book/default/chapter/04#API)Sunday, December 11, 11
  • 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-developersSunday, December 11, 11
  • 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
  • Thank you childish wont-let-go nickname: blackthorne blackthorne (geek) bthorne_daily (social) francisco@ironik.org (PGP key: 0xBDD20CF1) http://www.digitalloft.org (homepage)Sunday, December 11, 11
  • web2py app defaults • menu • web2py_ajax (jQuery) • auth, mail, download and services • english default lang translation • generic viewSunday, December 11, 11