So you are old fashion? So am I. The web2py admin is nice but sometimes it gets in the way. Here is how you install and develop web2py apps without using admin. (Mind that in web2py “admin” refers to the web based IDE, while “appadmin” referes to the web based database administrative interface).
Download, Install and Start
$ wget http://web2py.com/examples/static/web2py_src.zip $ unzip web2py_src.zip $ cd web2py $ python web2py.py -i 127.0.0.1 -p 8000 -a 'chooseapassword' &
web2py is now installed and running. You can try it:
http://127.0.0.1:8000/
‘chooseapassword’ will be used in case you later decide to use admin. If you set an empty password the admin interface is completely disabled.
My First Application
An app in web2py is a folder. At a minimum it needs a controller action else it does nothing. We are going to create a simple action that says “Hello World”
$ cd applications $ mkdir myapp $ mkdir myapp/controllers $ echo 'def index(): return "Hello World"' > myapp/controllers/test.py
Done! Now you can try it.
http://127.0.0.1:8000/myapp/test/index
(Notice that there is nothing else to type to deploy the app, nor there is any metadata anywhere).
Exploring “myapp”
By calling the app, web2py has created the proper folder structure, which we can explore:
$ cd myapp $ ls models (the data representation) controllers (logic and business flow) views (presentation) static (css, js, images, etc) modules (anything to be reused) languages (translation files) cache (shelves for cache.disk) databases (.table, sql.log and storage.sqlite) sessions (unless session disabled or in DB) errors (all tracebacks logged here) cron (contains web2py crontab) private (any other files needed by the app) uploads (files uploaded by the app)
Currently all the folders are empty except for controllers/ which contains test.py and sessions (since each user is associated to a session file unless disabled).
Deploying an existing app
Deploying and app is as easy as zipping an application folder and unzipping it under a different web2py installation. For example if you want to install the CRM shown here all you need to do is
$ cd ../ $ mkdir mycrm $ cd mycrm $ wget http://web2py.com/appliances/default/download/app.source.9ee5fc505dd76ea2.7765623270792e6170702e63726d2e773270.w2p $ tar zxvf app.source.9ee5fc505dd76ea2.7765623270792e6170702e63726d2e773270.w2p
And now the CRM up and running at
http://127.0.0.1:8000/mycrm
You can manage it form
http://127.0.0.1:8000/mycrm/appadmin
web2py apps are normally distributed as .w2p files. They are just tar gzipped folders.
Request Variables
Request variables are in request.vars. Here is an example
$ cd ../myapp
$ echo '
def index():
return "Hello %s" % request.vars.name
' > controllers/test.py
Now if you call
http://127.0.0.1:8000/myapp/test/index?name=John
You get
Hello John
Session Variables
Each visitor is uniquely associated to a session. If for example you want to count how many times the visitors loads the index URL:
$ echo '
def index():
session.my_counter = (session.my_counter or 0)+1
return "You have been here %s times" % session.my_counter
' > controllers/test.py
Now if you now visit
http://127.0.0.1:8000/myapp/test/index
You get
You have been here 3 times
(notice that session.anything returns None if anything is not stored in the session)
Views
If an action (i.e. a function in a controller) returns a dictionary. the output is rendered by a view. A view can be .html, .json, .xml or any other extension. You specify the extension in the URL (defaults to html). If a view is not present web2py uses a generic one to try render the dict. For example:
$ echo '
def index():
return dict(message="Hello World")
' > controllers/test.py
$ mkdir views/test
$ echo '
<html><body><h1>{{=message}}</h1></body></html>
' > views/test/index.html
Now if you now visit
http://127.0.0.1:8000/myapp/test/index
You get
<html><body><h1>Hello World</h1></body></html>
Notice that {{=message}} automatically escapes the variable message before printing it to avoid XSS injections.
Layouts
It is common to define a layout so that all pages look similar:
$ echo '
<html><body>{{include}}</body></html>' > views/mylayout.html
$ echo '
{{extend "mylayout.html"}}
<h1>{{=message}}</h1>
' > views/test/index.html
The content of the index.html view replaces the {{include}} of the extended view.
Database Models
Let’s create a simple app that allows users to post comments and read each other comments:
$ echo '
db = DAL("sqlite://storage.sqlite")
db.define_table("message",Field("body",requires=IS_NOT_EMPTY()))
' > models/db.py
$ echo '
def index():
form=SQLFORM(db.message)
if form.accepts(request.vars):
redirect("index")
messages = db().select(db.message.ALL)
return dict(form=form, messages=messages)
' > controllers/test.py
$ echo '
{{extend "mylayout.html"}}
<h1>Post a Message</h1>
{{=form}}
<h1>Previous Messages</h1>
{{for message in messages:}}<p>{{=message.body}}</p>{{pass}}
' > views/test/index.html
Now if you visit the usual url you get a form with built-in validation that displays errors (if submitted values for no pass validation) and displays a list of all posted messages.
Notice that You DO NOT NEED to create the table ‘message’ or access the DB using third party tools. web2py takes care of it for you automatically.
If you want the database administrative interface
http://127.0.0.1:8000/myapp/appadmin
copy from the welcome folder into your app the following files
controllers/appadmin.py views/appadmin.html views/layout.html views/web2py_ajax.html static/*
Cloning an app
Normally you do not start from scratch. For example you may want to start from a clone of the scaffolding app “welcome” (this is what “admin” does when you create a new app).
$ cd ../myapp $ cp -r ../welcome/* ./
The scaffolding app includes a lot of useful stuff such as “appadmin”, “auth”, “crud”, “service”, secure upload/download, generic views, default layout and some Javascript/Ajax tools.
Deploying the app on Google App Engine
To deploy an app on GAE edit web2py/app.yaml (already provided) and specify your GAE application id.
Replace
db = DAL('sqlite://....')
with
db = DAL('gae')
and deploy it
appcfg.py update web2py/
The last line must be executed from outside the folder that contains web2py.
Interactive mode
You can enter into interactive mode for any specific app
$ python web2py.py -S myapp -M >>> print db.tables ['message'] >>> print db.message.fields ['id','body'] >>> db.message.insert(body="this is a test") 1 >>> db.commit()
Your code would be executed as if it were in a controller. You have to db.commit() or db.rollback() explicitly.
Use web2py.py -h for more command line options.
Philosophy
Web2py controllers and models are executed, not imported (this is different from any other Python framework and similar to Ruby on Rails). This means they DO NOT “import web2py” but they CAN “import any_other_module” you may need.
There is no meta-data stored anywhere.
There is no process monitoring files for changes.
In web2py there is a single event (the http request). When an http request arrives, web2py locates the requested app/controller/action, re-creates any folder that may be missing, creates any database table that is required (or alters the db appropriately), executes the models, the requested actions and its associated view. If the app uses the db, everything is done in a transaction. Any uncaught error exception triggers a rollback and a ticket is issued to the user. All errors are logged. Errors are in the myapp/errors folders and they are just Python pickles which contain the traceback.
If you clone “welcome” everything has a default: each model has an “appadmin” interface and each action has default generic views in html, json, and xml.
About the Author
Massimo was born in 1971. He has a Ph.D. in High Energy Physics. He is an Associate Professor of Computer Science and the Director of the Master in Computational Finance at the School of Computing of DePaul University in Chicago. He is the lead developer of web2py.