People are trying to hack into this site every day to post inappropriate material, so edit access is blocked. If there is anything incorrect stated about Django here, please email me and it will be fixed. It is my interest to post correct and unbiased information.
We really like Django and web2py has taken inspiration from Django.
If we say anything wrong about Django please let us know and we will correct it.
These are just some tips on how to move a Django project to web2py, it is not a comparison
Notice that web2py is not based on Django although it has some similarities in the syntax
Many of the Django examples below are from the Django documentation page
Click here for a detailed feature comparison between web2py and other frameworks.
Click here for a comparison with TG
Click here for a comparison with Rails (work in progres)
Django and web2py are both MVC frameworks but what Django calls a view, web2py calls a controller and what Django calls a template we2py calls a view. We are sorry for the confusion but the web2py naming convention is the standard one.
Both Django 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
Django has urls.py, web2py has routes.py. In web2py the use of routes.py is optional and a path /a/c/f maps into a call to function f() in controller c.py in application a. You only edit routes.py if you want to change the default behavior.
The equivalent of this urls.py in Django
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^polls/latest\.php$', 'mysite.polls.views.index'),
)
In web2py would more or less be (in the routes.py) file:
routes_in=(
('/polls/latest\.php', '/polls/views/index'),
)
In web2py you can also define reverse routes (routes_out) and set routes filters by remote address.
This is an example of a Django model:
from django.db import models
class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
This is the same in a web2py model:
db=DAL('sqlite://mydb.db')
db.define_table('poll',
Field('question',length=200),
Field('pub_date','datetime'))
Notice that:
You can use the interactive model builder for generate web2py models.
To insert records in Django
p=Poll(question='What's up?',pub_date=datetime.datetime.now())
p.save()
To insert records in web2py
p=db.poll.insert(question='What's up?',pub_date=datetime.datetime.now())
Notice that:
To select some records in Django:
rows=Poll.object.filter(pub_date__year__gt=2005)
To select some records in web2py:
rows=db(db.poll.pub_date.year()>2005).select()
The following Django view:
from django.shortcuts import render_to_response
from mysite.polls.models import Poll
from django.http import HttpResponse
def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
In web2py would be
def index():
latest_poll_list=db().select(db.poll.ALL,orderby=~db.poll.pub_date,limitby=(0,5))
return dict(latest_poll_list=latest_poll_list)
Notice that:
In Django you raise errors with
from django.http import Http404
raise Http404
In web2py you raise errors with
raise HTTP(404)
and you redirect with
redirect(URL(r=request,f='index'))
Which redirects the visitor to the 'index' controller function within the same application/controller.
Notice that:
In Django the view for the above controller function index() would look like
<html><body>
{% if latest_poll_list %}
<ul>
{% for poll in latest_poll_list %}
<li>{{ poll.question }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
</body></html>
In web2py the same output could be produced by
{{extend 'layout.html'}}
{{ if len(latest_poll_list): }}
<ul>
{{ for poll in latest_poll_list: }}
<li>{{= poll.question }}</li>
{{ pass }}
</ul>
{{ else: }}
<p>No polls are available.</p>
{{ pass }}
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 Django:
from django.utils.translation import ugettext as _
_('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_poll form in web2py
def create_poll():
form=SQLFORM(db.poll)
if form.accepts(request.vars): response.flash='poll posted'
elif form.errors: response.flash='there are errors!'
return dict(form=form)
we could not figure out how to do this concisely in Django so we did not list it here.
Notice that in we2bpy:
Django validators are functions and they are used as in the following example
from django.core.validators import isValidEmail
EmailField(...,validator_list=[isValidEmail])
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 Django and web2py use doctests for testing.
In web2py, the administrative interface provides a button to run all the tests for you app and writes a report.
In Django you need to setup the cache at the framework level and then use it to store/retrieve objects or cache controllers as in
@cache_page(60*15)
def index(request): ...
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 (same as Django) 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.
web2py comes with jQuery base.
Both Django and web2py run on Google App Engine but, in the case of Django, you have to rewrite your models, your insert and your select to use the app engine API. In the case of web2py most of the ORM functionality will work as is on the app engine.