We really like TurboGears and web2py has taken inspiration from some TG features.
If we say anything wrong about TurboGears please let us know and we will correct it.
These are just some tips on how to move a TurboGears 1.0 project to web2py, it is not a comparison
Notice that web2py is not based on TurboGears although it has some similarities in the syntax
Many of the TurboGears examples below are from the TG documentation page
Click here for a feature comparison between web2py and other frameworks.
Both TG and web2py have a shell. Web2py also has an administrative interface that allows you create, import, delete, export, design/edit, debug, test, and administer you app, so you do not need to use the shell. Here is a demo web2py also provides an ajax web-based python shell to interact with the apps and their models.
You can start the text-based shell with
python web2py.py -S admin
You can get the ajax shell and other ready made web2py apps from the repository of appliances
There is also a Ulipad Shell Plugin
This is an example of a TG model:
#import SQLObject, UnicodeCol, etc. etc.
class Page(SQLObject):
pagename = UnicodeCol(alternateID=True, length=30)
data = UnicodeCol()
This is the same in a web2py model:
db=SQLDB('sqlite://mydb.db')
db.define_table('page',
SQLField('pagename',length=30),
SQLField('date','text'))
Notice that:
You can use the interactive model builder to generate web2py models.
To insert records in TG
p=Page(name='name', data="")
To insert records in web2py
p=db.page.insert(name='name', data="")
Notice that:
To select some records in TG:
pages=Page.select(LIKE(Page.q.name, %am%"),orderBy=Page.q.pagename)
To select some records in web2py:
pages=db(db.page.name.like('%am%')).select(orderby=db.page.pagename)
The following TG view:
import turbogears
from turbogears import controllers, expose
from wiki20.model import Page
from docutils.core import publish_parts
class Root(controllers.RootController):
@expose(template="wiki20.templates.page")
def index(self , pagename="FrontPage"):
page = Page.byPagename(pagename)
return dict(page=page)
In web2py would be
def index():
page=db(db.page.name==request.vars.pagename).select()[0]
return dict(page=page)
Notice that:
In TG you redirect with
import turbogears
raise turbogears.redirect("/", pagename='index')
In web2py you redirect with
redirect(URL(r=request,f='index'))
It redirects the visitor to the 'index' controller function within the same application/controller.
Notice that:
In TG the view for the above controller function index() could look like
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'">
<head>
<meta content="text/html; charset=utf-8"
http-equiv="Content-Type" py:replace="''"/>
<title> ${page.pagename}</title>
</head>
<body>
<div style="float:right; width: 10em">
Viewing <span py:replace="page.pagename">Page Name Goes Here</span>
</div>
<div py:replace="XML(data)">Page text goes here.</div>
</body>
</html>
In web2py the same output could be produced by
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta content="text/html; charset=utf-8"
http-equiv="Content-Type" py:replace="''"/>
<title>{{=page.pagename}}</title>
</head>
<body>
<div style="float:right; width: 10em">
Viewing {{=page.pagename}}
</div>
{{=XML(page.data)}}
</body>
</html>
Notice that:
In web2py form variables are in request.vars and they can be accessed by
request.var.myvariable or request.vars['myvariable']
The first notation returns None if not request.vars.has_key('myvariable'). The second raises an exception. You can use request.post_vars
to get only post vars and request.get_vars
to get only get variables.
To store stuff in session you do
session.myvariable=3
and you retrieve it with
myvariable=session.myvariable
The response object is used to stream data, create xmlrpc services and send some standard variables to the views.
In TG:
_('this is a message')
In web2py:
T('this is a message')
(and as usual no need to import anything since you are supposed to use T) You web2py you can also do
T('this is message %(name)s',dict(name='xxx'))
it-it.py
) in the admin interface.web2py also has helpers to create HTML for example
{{=A('here',_href=URL(r=request,f='index')}}
produces the same output as
<a href="{{=URL(r=request,f='index)}}">here</a>
Helpers can be nested as in
HTML(BODY(H1('title'),P('bla '*10,_id='main')))
and they can be used to build forms via FORM and INPUT.
Notice that web2py escapes all text displayed in views to prevent XSS. Only text marked by XML('...') is not escaped.
Here is how to create a create_page form in web2py
def create_page():
form=SQLFORM(db.page)
if form.accepts(request.vars): response.flash='page posted'
elif: form.errors: response.flash='there are errors!'
return dict(form=form)
Notice that in we2bpy:
web2py validators are objects which means they take parameters (for example the error message on failed validation)
db.mytable.myfield.requires=[IS_EMAIL(error_message="invalid email")]
IS_IN_DB
and IS_NOT_IN_DB
check whether the values is or is not already in the database. IS_IN_DB
it is automatically rendered as a select/option input field.Both TG and web2py can use doctests for testing.
In web2py, the administrative interface provides a button to run all the tests for you app and writes a report.
Sorry, I do not know how to cache in TG.
In web2py there is no configuration to do. There are two built-in caching mechanisms cache.ram and cache.disk and other plugins (memcache). You can use them as follows:
@cache(request.env.path_info,time_expire=60*15,cache_model=cache.ram)
def index(): ...
The first argument of cache is the key to be used for caching the function, the second is the expiration time in seconds and the third is the cache type. You need to specify because you can use different caching mechanisms within the same ap. You can also use cache.ram and cache.disk to cache any function, select and view.
If you really like memcache you can define cache.memcache by doing
from gluon.contrib.memcache import MemcacheClient
memcache_servers=['127.0.0.1:11211']
cache.memcache=MemcacheClient(request,memcache_servers)
and then use cache.memcache in place of cache.ram.
TG uses Dojo. web2py comes with jQuery base. But with any of them you can use any JS library.
In TG:
class Root(controllers.RootController):
@expose(template="wiki20.templates.page")
@expose("json")
def pagelist(self):
pages = [page.name for page in Page.select(orderBy=Page.q.name)]
return dict(pages=pages)
In web2py
import gluon.contrib.simplejson as sj
def pagelist():
pages = [page.name for page in db().select(db.page.nane,orderby=db.page.name)]
return sj.dumps(dict(pages=pages))
web2py comes in one executable package including an SSL enabled web server, the sqlite database, a web administratve interface that allows you to create/edit/deploy and manage all your applications.
Exception are automatically caught by web2py which logs the traceback, the code causing the exception, and issues a ticket to the visitor that triggered the exception. No code is exposed to the visitor, not even by mistake, ever.
web2py includes libraries for generating CREATE/UPDATE/DELETE forms from your database tables.
web2py incudes libraries for handling AJAX, JSON, REST, RSS, ATOM, RTF, CSV, WIKI (markdown) and some more protocols.
web2py has helpers that help you build objects that can be serialized in HTML or XML. Any correct HTML/XML can be generated using exclusively helpers.
web2py code runs on the Google App Engine.
web2py packages everything you need in one binary file that you don't even need to install. I keep mine on a USB stick. You just click on it and it start web server, the sqlite database, fires the browser for access to the administrative interface.
web2py deals with static files for you, streams them when they are large (both in upload and download), and automatically supports IF_MODIFIED_SINCE
and PARTIAL CONTENT
. You can do streaming audio and video without any extra tools or settings.
web2py can map URLs using regular expressions so that you can use it to handle legacy URLs.
web2py has no configuration files. You just create an empty app via the shell or the web based admin interface and create/edit your models, controllers and views (using an editor or the web based admin interface).
There is a repository of free web2py apps here and an interactive FAQ there.