Python – web2py or Django

For my own personal work and reasons, I’ve been moving as much of my non-browser based development into the world of Python as I can manage.  Any reasons why are sort of beyond the scope of this and I might write them out sometime later.  But for the time being, I wanted to discuss the question of Python web development.

Being a contrarian by nature, I automatically did not want to use Django as it is widely the most popular and utilized Python web framework.  When I started looking into Python, I wanted it to work just like the PHP I had cut my teeth on, so that drew me to mod_python and its Python Server Pages.  But mod_python has not been supported or developed for a long time and the technology it is based around are a bit outmoded.  So I was forced to look at WSGI compatible applications in the family of Django and others.

Now my requirements for a framework, after working with raw PHP when I first got started and then a custom framework are rather straightforward.  I want a solid database abstraction layer (DAL) that functions in an object-relational mapping (think: akin to Hibernate, and feeling natural to the flow of the rest of the language I’m using, supporting its natural data structures and the like) while isolating me from my choice of database or storage.  I also want it to have very solid and integerated JSON and non-HTML support.  I was spoiled with the proprietary PHP framework I used by its solid and seamless integration of a JSON output mechanism.  I also want it to do all the heavy lifting for me, while leaving me feeling powerful and still in control of the flow of my program.

So I stumbled across web2py and have been toying with that.  I have also recently been convinced to give Django a try.  The following are my impressions – those of a solo developer working on relatively simple pages and sites while laying out a plan and framework for a larger project, so consider the opinions in that light.


ORM – Object Relational Mapping

Both web2py and Django have excellent Object-Relational mapping layers in their database libraries.  For both frameworks the developer will define an object type which the framework will transform into a SQL table or tables.  In Django you do this by creating a class which extends Django’s Model class.  The fields you define all need to be instances of the different field types.  Then, you fetch the objects or create them like natural Python objects, calling the .save() method when you want to write out the changes to the database.  This is a bit more Pythonic than the web2py mechanism of calling on a method of the DAL object.

With web2py’s method, however, all models are contained on the explicitly declared DAL object (often named “db”) and accessed that way.  So to access the person objects you refer to db.person.  In Django you would simply refer to the Person class you’ve declared.  In my thinking, containing all of the database-driven models on a database object feels safer than having them be free-standing classes.  However, the Django model classes are more Pythonic in their feeling.  Creating a Django model for a person would look like
person = Person() = "John Doe"
person.gender = "Male"
person.occupation = "gardener"

In web2py, this would look like
db.person.insert(name="John Doe", gender="Male", occupation="gardener")

Obviously the Django method feels more like manipulating a regular Python object, but I like the namespacing of the web2py which makes it explicitly obvious we are doing a database transaction.  If only they were brought together somehow!

Another way Django wins out here is with ManyToMany fields.  These are the types of relationships where, for instance, Bob and Alice together own a Ford and a Chevy.  Each car is owned by two people and each person owns two cars.  In Django, when defining the person, I would simply add a field called car that was an instance of a many-to-many relationship, and then I could access any cars a person owns by accessing a property on my object (I believe through something like person.cars_set) which is a list of the cars that person owns.  Similarly Django automatically creates the reverse relationship on a car by linking it to an owner.  In web2py, the developer needs to explicitly create the person-car ownership table and give it the two foreign key links.

However, web2py exposes an interesting mechanism here to create what are essentially views in the database from a Pythonic interface which makes dealing with the resultant relationship very easily and can be extended to any other frequently used relationship or query.  Given a definition of person, dog and ownership like this

    Field('person', db.person),

I can then define the view of all people with dogs and all dogs with owners like this
person_dog = db(( == db.ownership.person) & ( ==
Now I can iterate on all of the person-dog pairings by a call like

for row in

And I can search for all of Bob’s dogs by asking for

for row in person_dog("Bob").select():

and similarly for the owners of Fido by changing my arguments to person_dog().

This view functionality is very powerful, just as SQL views can be very powerful. Wrapped up inside of the DAL as it is, I don’t know if these are actual SQL views, but they make dealing with some very common relationships within your models very easy. It need not be related to many-to-many relationships. I haven’t come across an equivalent pre-defined mechanism within Django, though it is probably achievable by creating member methods on a model class.

I have to say, though, overall Django wins out as more Pythonic in the DAL and the encapsulation of the many-to-many relationships, even if I slightly prefer web2py for its namespacing of the database objects and its powerful views which come more or less for free.

Database Support

I was surprised, when I looked at the list of supported Django databases, that I only saw listed MySQL, Oracle, Postgres and SQLite.  Although these are all the databases I have used myself, and therefore it is sufficient for my own work, I must say I am surprised at how short the list is.  I didn’t see any mention in the documentation of supporting third-party contribs or anything else like that, although Django says you are free to incorporate any ORM layer you want.  web2py, on the other hand, claims native support for SQLite, MySQL, Postgres and Oracle in addition to MS SQL, FireBird, DB2, Ingres and the Google App Engine if you happen to be running in that environment.

If you really require your DAL to be database-agnostic and usable anywhere, web2py holds about twice as many cards as Django here.  Very impressive, and very useful, especially if you use or want to use Google App Engine.  There are a few others mentions of GAE support throughout the framework documentation, so it seems to be something web2py takes very seriously as a support point for their software.

Heavy Lifting

In Django, when a request comes in for your controller (Django calls these Views), your method is called just as it would have been called in a traditional Python app.  If you want access to your own models or extra libraries or anything of that type, you need to import them.  If you want to return a value to the user that is not an error message, you can to call a templating engine, retrieve its results as a string, construct an HttpResponse() object and pass it the string which will be returned to the user.  If there is a problem with your database access, you need to raise your own 500 errors.  I have to design an app-specific way of determining what format of output the user is looking for (HTML, XML, RSS, JSON?).  After I have defined a database schema, or changed it, I have to manually issue some command line operations to inform Django that it needs to update the schema.  To me, these represent areas where Django isn’t even a finished framework.  There is too much here for me to do, if I just want to get my application up and running.

In web2py, I’ll address each of the above issues and where I think the web2py offering is stronger than Django’s.

  • Extra imports: In web2py, the base functionality is already imported for me in my controllers (Django’s views).  My database object with all my models, web2py’s request and response objects, and a few basic system environment objects.  These are functionality basic enough to dynamic web programming that to me a framework which does not include them already is asking more of me than it ought.  Perhaps a bit PHP-like of my thinking, but I consider this a major plus for web2py.
  • Response values and errors: Of course, if I want to call methods like redirects or errors in web2py, the response object is already created.  Instead of raising an error myself, I can just tell the response object what error code to return.  And instead of being limited to returning an instance of HttpResponse() the way Django requires, in web2py I can return a string or a dictionary.  If my response has to be wrapped in an HttpResponse() anyway, why make the programmer explicitly create it?  The different types of return values are handled differently by web2py based on…
  • Output format: With Django, I need to create and retrieve a string myself, pass that to my HttpResponse() object, and return that from my view.  In web2py, there is a proper View/Controller separation.  If I want to return a string, I am free to do that, and that string will be returned verbatim to the user.  However, if I return a dictionary, web2py quietly calls the view (Django would call it a template) associated with the current controller, expanding each of the keys of my dictionary to be a global variable inside of the view. If the request came in with a .html extension or no extension, the associated HTML view is rendered
    However, if I want the dict object directly encoded, I need only append a “.json” onto my URL and the associated JSON view will be called.  The included default JSON view will generically encode the values of the dict into a JSON string for return to the user – no work needed by me.  I don’t even need to call a JSON library to stringify the dictionary.  One view, transparently available in both HTML and JSON.  Likewise I can add a .rss to the URL for the RSS view to be rendered instead.  The same with a .xml extension.
    Of course, as the programmer, I am free to override the default or force a particular view format to be rendered, also I can request a view other than the default view, but there are defaults and they are straightforward to work with, whereas with Django, I have to specify each of those values manually.
  • Changes to schema: Now this one I’m not so certain about.  If you change the value of your database models at any time, web2py will automatically attempt to adjust your database schema the next time you load the models file.  This can be a blessing or a curse.  The blessing is that your ORM API is never out of sync with your database.  All you do is update the model file, refresh your page, and you have the new models.  On the other hand, lots of developers are wary of anything touching their database.  The explicit invocation of a migration path, including manual supervision, the way that Django allows is nice.  Web2py has the same manual shell interface available for running a custom upgrade path, so it’s not like the framework is forcing you to accept the upgrade, and it also has a way to specify custom automatic upgrading and conversions.  But it could be worrisome for some types of changes and migrations (particularly moving columns or altering their types).  Still, the hybrid of automatic, behind-the-scenes work done by the framework and the power of the manual operations gives web2py an advantage from my point of view.

JSON Support

I have already touched on this above.  JSON support is as easy as tagging the end of your URL with a “.json” in any case where you return a dict from your controller (this is the “normal” or “expected” behavior of a web2py controller, though not required).  This makes migrating portions of a website from HTML to AJAX drop-dead easy.  It also makes programming sites to support people who do not run JavaScript much easier than it otherwise would be.  As long as your views are already in place for the static site, you need only incrementally update your site to capture link clicks, tag the .json on the end, and render the JSON on the browser side.

Any experience with either?  What do you think?

Friday, January 21st, 2011 Server, Technology

30 Comments to Python – web2py or Django

  • [...] This post was mentioned on Twitter by Bruno Cezar Rocha, Gilson Filho, Gilson Filho, web2py Brasil, Greg Hellings and others. Greg Hellings said: New Blog Post: Python – web2py or Django @web2py @djangoproject [...]

  • [...] Read the original: Python – web2py or Django » Greg's Blog of Awesome [...]

  • lebakwatery says:

    Hi, nice topic. Enjoy very much. Thanks.

  • Luke Plant says:

    It was interesting to me that everything you mentioned as a plus for web2py is something that I would hate to see in Django, and think is a strength of Django (and I’m speaking as a core dev) :-)

    Automatically sticking things into the namespace is one of the things about PHP that is horrible, and the *last* thing I would ever want to copy, apart from potentially some Python based config file. Even in scripts as simple as fabfiles (Fabric), you still import all your dependencies.

    Copying this misfeature of PHP in Python means that your code is not straightforward Python modules any more. I don’t know where web2py is with modular applications, but Django applications are normal Python packages that are can be installed from PyPI and conform to the normal rules and expectations of Python code. When reading Python, I expect to be able to look at something called ‘response’ and see where it has come from if it is not defined in the local code.

    Global response objects that are already created means you create lots of side-effectful code that is difficult to maintain. Any chunk of code can access request and response objects, without any thought to whether that is a good idea. This tends to make separation of concerns very difficult, and difficult to run the code in a non-web context (which is common for Django projects – they are just Python, after all).

    Django defines a view to be ‘a function that takes a request and returns a response’. That allows the function to be defined and tested cleanly, and allows complete flexibility with implementation – including returning some object that does not inherit from HttpResponse at all (as long as it has the same interface).

    Automatically converting return values into different return types is something you can do very easily with a piece of middleware in Django, but requiring ‘.html’ or ‘.json’ extensions on the path for everyone is not the kind of decision we want to make. Personally I think URLs look much cleaner and more friendly without .html stuck on the end.

    It is also trivial to use or define shortcuts for different types of responses, or decorators to do the automatic adjusting. The more of that kind of automatic logic you bake into the core, the more you reduce the options for the developer.

    With schema adjustments, I’m extremely glad that Django does not do anything automatically – that sounds like a recipe for disaster. We have various solutions for doing migrations in a controlled way (South is the leading contender), and I really don’t think that any automatic solution is ever going to be good enough to be relied upon when your production database is at stake.

    • mdipierro says:

      Just clarify. Almost everything that web2py does by default can be changed. For example if you request an action with .json, web2py looks for a user defined template to convert the dictionary into json for that action. If it does not find it, then it follows the default behavior. Having a default behavior for everything is in fact a major design difference between web2py and Django. Just do not make the wrong assumption that default behavior cannot be changed.

    • greg.hellings says:


      Thanks for the input! I certainly understand not wanting to import all sorts of things into the namespace to pollute it with copious amounts of methods and globals the way PHP has all of its core modules imported to every page. But asking a developer to import every item, even ones like request and response which (I believe) is reasonable to expect will be used in near 100% of controllers and views… I consider that just a convenience issue that I’d rather not have to deal with if I can help it.

      The automatic importing of my application’s models – I can see the reasonableness of not wanting those imported in every controller and view/template, but I’m willing to have those imported automatically if it means I don’t have to remember every path to request and response for every method. Other portions of the web2py framework, even very commonly used ones, require explicit importing. But those very most common ones are automatically handled.

      Web2py seems to consider (I can’t say this as a dev, only as an observer and user) a web2py app ought to never be run outside of web2py either on a server or its equivalent of $./manage shell. Thus the app does not need to be a standalone Python module. I can see the benefits of wanting them to be so, but I web2py’s applications are close enough as to still be familiar from a Python developer’s perspective. The only real differences are auto-import of the request, response and models and the lack of an file. All things which just simplify the process, so I’m happy to accept them.

      Django does not require a ‘.html’ or ‘.json’ extension to set the output format. If I make a request to “/app/controller/function” OR to “/app/controller/function.html”, the default output web2py gives is in HTML. In my function, I can set that to always be JSON or to be based on a different decision. Similarly, “/app/controller/function.json” will call the same function, defaulting to JSON output – unless I have changed it to always be a particular format, regardless of the extension. Again, providing a mechanism to handle that in Django is good, but I prefer it to be automatically included, with me having the option to override or disable that default easily. Just, again, a convenience issue for me.

      My options aren’t reduced in any way that I have seen by taking the decisions into the core – they’re just given default values with an easy way to override, instead of relying on me to define the defaults. Again, just an ease-of-use.

      Schema adjustments, I can understand wholeheartedly. It would certainly make me nervous and I would definitely want to check on the behavior and web2py’s defaults if I was doing anything other than just adding a table or adding fields to a table. I do know that you can add a flag to each model to tell web2py not to update it automatically, and then you could bring up the web2py shell to run a manual migration tool. I don’t know if there is a pre-canned app or plugin like South to handle that, but if you’re already writing the manual migration, writing it manually with web2py can’t be all that more difficult!

      Thanks for the feedback, Luke! I appreciate hearing your insider’s opinion on Django.

      • mwolfe02 says:


        Nice article. I just wanted to add that you can easily turn off the automatic migration of database schema in one place: when you define the db variable. For example:

        db = DAL(‘…’, migrate=False)

        If you define multiple database connections (something you can easily do in web2py) you would have to do it for each database connection you define:

        db = DAL(‘…’, migrate=False)
        auth_db = DAL(‘…’, migrate=False)

        So if you don’t want automatic migrations (I don’t), it’s not exactly hard to opt-out.


      • Brian Luft says:

        Thank you for your writeup. I agree across the board with Luke, but as far as web2py potentially bringing new people into the Python community I support their efforts and hope they succeed. It could be said a little animosity has developed between the two camps, largely over a few of these “convenience” details that are either minor or major points of contention depending on your overall philosophy.

        One of Guido’s underlying philosophies for Python is that code is read much more than it is written and this is probably why “Explicit is better than implicit” is #2 on the Zen of Python. I’m all for conveniences and I credit web2py on a nice piece of social engineering by selling this “benefit” to potential users but I still don’t see what purpose it really serves. Automatically adding the necessary imports to each file would accomplish the same thing and it would give any reader of the file some idea of what the names being referenced are. In this sense, it feels like the web2py team has made a choice to go against Python idioms and recommended best practices.

        If you’re not as concerned about a project that sort of “goes against the grain”, make sure you consider whether a few code-level conveniences are worth potentially giving up full control of the request/response cycle. I’m not familiar with enough with web2py to draw comparisons, but like Luke said, being being able to manipulate the response content down to the byte is an important capability to have and Django still provides a nice high-level abstraction on top of that. The baked-in conveniences you’ve described are almost always a few-line utility function away and I’ll reuse those utilities across projects. Just make sure you can evaluate whether both frameworks give you the flexibility to redefine any part of the pipeline when you need to.

        Having used South for several large projects, I can tell you that I wouldn’t want to trust any migration tool that tries to do too much behind the scenes. South does a great job of doing the heavy-lifting for trivial transformations and getting out of your way the rest of the time. That said, there are a lot of common scenarios where it is not easy to represent the operations in a trivial manner. Make sure your migration tool has a clean path for being able to test changes in a sandbox, rolling back, etc.

        Did you take a look at how the generated SQL looks for each framework? Does web2py add any additional queries behind-the-scenes?

        Other things to keep in mind:

        Momentum – Django has a large and growing community with a healthy ecosystem. Even if you can’t find an app that does exactly what you need chances are you’ll find something that provides a great starting point.

        Battle tested – I know firsthand and know of other large Django projects being run in production.

        Flexibility – Subjectively, I feel like Django maps a little better to some of the other frameworks/micro-frameworks. For example, I know that given a Django app I could write a one-off service in Flask reusing the models and templates from the Django app.

        TL;DR – IMO web2py feels slightly more “we’ll do it this way because we think it makes things easier for you” whereas Django feels slightly more “we’ll let you do things your way because we think it will make things easier for you”.

        • Anthony says:

          Brian, thanks for your comments. Although your points about explicitness and imports are well taken, I think the concern about explicitness in web2py is overblown. In both the web2py framework code and web2py apps, most objects/modules are in fact explicitly imported, as per Python norms. However, there are a few core objects that are already imported into the execution environment (see Note, most of these objects are simply HTML helpers (with the same names as their HTML tag counterparts) or form/database validators (e.g., IS_DATE). Aside from the helpers and validators, there are only 9 other global objects, and they are all well documented. These include key objects such as request, response, session, and cache, which are used everywhere and well understood. If you see these objects in some code, it’s not difficult to understand what they are or where they came from.

          It’s also not clear that explicit import statements would help all that much. Even if you saw these objects referenced in an import statement, that wouldn’t tell you much about what they are or how to use them. You’d still have to go to the documentation. Even if you think the import statements are absolutely critical, though, it’s not really a fundamental flaw because you could always just insert them anyway (commented out or inside an ‘if 0:’, since they’re not really necessary).

          It’s also worth pointing out that although web2py has a lot of conveniences and default behaviors, it’s also easy to over-ride those behaviors and customize things, or even plug in alternative libraries in some cases. Also, web2py is a WSGI application and allows the use of third party WSGI applications and middleware.

          Note, a major goal of web2py is ease of use, from setup, to learning, to coding, to distribution, to deployment. I think it manages to achieve that goal quite well while offering a very rich feature set and allowing a lot of flexibility. It’s also constantly improving (with new commits every day and new releases every 2-4 weeks), and it has attracted a very active, friendly, and helpful community that is growing quickly.

  • [...] is another python famework that supports Firebird out of the box , the question is if is worth investigating it (No Ratings Yet)  Loading … Permalink Leave your comment [...]

  • mariuz says:

    Django support for firebird is hosted in an external project with support for django 1.2
    it works in production on several sites but it should be in the end integrated into the main

  • [...] examples and free code to learn… much easier to understand than Django and (from not my only personal point of view) much more [...]

  • Mohammed says:

    Hi, Please Help me with this problem,

    I’ve created views in web2py and it works well, but the problem is; i need to create it in multiple languages. so if i am not mistaken i should handle ‘Dictionaries’.
    And I don’t know how?!

    • greg.hellings says:


      web2py has an entire technology to handle translation of strings within the programming, so that should be relatively straightforward. If you need to use different languages in your layout.html file, you can make your layout.html look something like this:

      {{if session.language != None:}}
      {{ include (‘layout-%s.html’ % (session.language,)) }}
      {{ include ‘layout-default.html’ }}

  • Mike A says:

    The thing that staggers me is how web2py takes python web development and makes it difficult.

    I have several years django experience, and I am well aware django has many warts. So I was initially attracted to web2py’s self-hype as a ‘better’ django.

    The project I started working on has a bunch of maintainers, I guess several years of effort, but no unit-tests. When I asked why they had no unit tests, they said they had tried to go that way several times, but had given up each time as it wasn’t worth it. I found this hard to believe, how hard can it be to write unit tests? You just write ‘em and run ‘em.

    Not so with web2py. I soon found out why it had been so difficult for them; because web2py code has the global environment, it has to expect the global environment, so any code that is run by unit tests must inject that global environment, which is actually really hard to do. So hard that it took me (an experienced python developer) a entire weekend to write a web2py nose plugin just so that I could run unit tests with nose. It would normally take about a minute to get cracking with nose: install it, type “nosetests”.

    The unit tests themselves are still, of course, flakey as hell because the code being tested often has to do all sorts of wacky global state abuse, which has to be reproduced by the tests. You can’t just pass a request to a function, you have to inject it into the test’s global state, with a load of other stuff. This slows down tests, as you have to set up the entire environment for each test. Also, nose has a problem because web2py can’t handle having the current directory changed, due to all sorts of assumption it makes on folder paths. This is not nose’s fault, this is web2py going against reasonable, accepted python standards.

    The global environment mechanism and other peculiarities in web2py, touted as features, clearly create huge problem in the medium to long term, as they create all sorts of difficulties interacting with other python tools and modules.

    What I believe I am seeing when I see people excited about web2py is this: those same aspects I’ve described which can kill a project in the long term, can indeed make it easier initially. Developers *do* save time at the *start* of a project by not having to write import statements, but then lose it when they are trying to figure out where something has come from, or how they are going to test stuff, or all sorts of other normally easy tasks in python. This is why experienced developers look on web2py with scorn. They simply know better. I sense cognitive dissonance when I point out these problems to web2py apologists. The rise to defend it, but quickly fall silent, agree with me or change the subject.

    I’ve seen people tout web2py as ‘the best-kept secret in web development’. But the reality is nobody is keeping it secret. Only those who have made an emotional or financial investment in it are trying to hype it, cos they need clients to believe in it, and they need more people to come into the small community. Smart developers, well paid developers at big companies, especially those with interesting blogs, simply aren’t using it, because they know what works and what doesn’t in the long term. That’s why we don’t hear about web2py.

    It’s a real shame, because it actually does have some other good features.

    • Speedbird says:

      It is interesting to see that most (if not all) of the unflattering comments towards web2py come from experienced django devs, I personally have worked on python (almost exclusively by the way) since circa 1998 (yes, started using it for “real work” back in the 1.4 version era), became a Zope, then Plone dev, then I had a choice of going to web2py or django, I think I took the correct turn when I chose web2py, my experience with it as a back-end developer is that the framework lets you work on the real problem, the “explicit better than implicit” part of the Zen is so subjective/overrated nowadays that it is almost out of context.

      I was able to create several relatively complex web apps in a matter of weeks (go to bitbucket and search for my name there), I am real proof that the web2py framework simply works and works fine.

      From all the “information” I’ve read online about this “web2py vs django” debacle, I’ve come to the conclusion that Django devs don’t like web2py because it “stuffs” all the global environment down your throat, or they don’t hate it because it uses “exec()” (OMG, blasphemy!!!), or they can’t stand it because it (conveniently) imports part of its core into one’s apps (how can this be??), they simply hate it because.. well, because it is simply not django, period.

      Best Regards,

      • Mike A says:

        Or they don’t like it because it makes interacting with 3rd party tools much more difficult.
        Or they don’t like it because it pollutes their names.
        Or how about they don’t like having to guess where things are being imported from.
        Or perhaps they don’t like it because global state is notoriously hard to reason about.

        Or maybe, like me, they feel justified in making a comparison based on practical experience with both frameworks (3 years real projects for django in my case, about 6 months real projects with web2py, and I started playing with web2py about 2 years ago). The other 6 developers on the project using web2py (a 3 year old project), are well aware of the issues I mentioned.

        BTW, do you have any django experience?

        It’s interesting that django devs often seem to know (as all programmers should) that:
        - globals are bad, because side effects can affect the entire system.
        - exec() to load code and modules causes problems because third party tools can’t reason about code coming out of exec, and odd things can happen like we may end up using multiple different copies of the same code/objects.
        - implicit magic makes code harder to reason about, as it is not obvious what is happening (Django went through a major branch called “magic-removal”, specifically to remove all this magic, which explains why they know this – people got burned by it).

        Perhaps most of the negative comments are coming from experienced django devs because most python web devs will be using django these days.

        Personally, I don’t hate web2py because it is “simply not django, period”, otherwise I wouldn’t have started playing with it (because, like I said, it has plenty of attractive features). But I do hate the amount of time I have to waste dealing with its import mechanism and debugging things in the global state. It’s a total deal-breaker for me. I can certainly understand how someone coming from Plone can prefer web2py though. If only web2py would get rid of the import mechanism and clean up its code, I’d be happy to use and promote it.

        I’ve listed real problems we experienced with web2py, but you rebut that with the tired old “bah, you just don’t like web2py cos it’s not django”. In fact, there are plenty of things I don’t like about django, the forms code is a mess, the queries lack expressiveness. The SQL layer doesn’t use bind variables AFAICT. I don’t consider myself a django dev (in fact I have a django t-shirt I never wear at events because I don’t want to be associated with django). Personally, if I were going to start a new project I’d use some micro-framework like pesto with SQLAlchemy rather than web2py or django. In doing so, I can pick the best modules for each job, rather than have one framework trying to do everything (although I should note that django explicitly aims to get along with other frameworks).

        I guess I consider myself a python dev. So, apart from the real, practical problems I have experienced with web2py, if I really am just having a gut reaction to web2py that’s probably the real reason – because it’s simply not pythonic, period.

        Best regards,


        • Speedbird says:

          Hi Mike,

          I have a relatively limited Django experience (nothing more than the creation of several minor applications after reading the book), but, why is this experience relevant in any case? – As far as any of the comments I have posted, I’ve made no negative references on the framework itself, if you want to feel superior providing extensive information indirectly “comparing” both frameworks and coming to a definite conclusion, fine by me, I hold no grudges for anybody or anything.

          BTW, do you have a college degree? (see my point?)

          We can spend eons debating on why web2py’s “implicit magic”, exec-ing-code-is-evil and the usual list (which it is getting bored), I totally understand the adversity against these sins, but they have a purpose and they are extremely well documented, really nothing to be ashamed of, and please point out *specific* “odd things” that can happen when executing a web2py application, or point to any security flaws (perceived or otherwise) that should prevent any pythonista from working with this framework, finally, I don’t “guess” my python background (I am proud to use this language!), I find it sad to hear you say that this framework is labeled “unpytohnic”, as I think it is exactly the opposite, I’d be interested to know what areas of these web2py applications you stated you worked on were, maybe some of the concepts of the framework were not well understood perhaps?



      • Mike A says:

        So I found and downloaded speedbird’s project qastack, a stack overflow clone.

        The beta is at

        There are 107 files. Not surprisingly, there are zero unit tests as far as I can see.

        I’m not attacking the project, there’s nothing wrong with it, it looks good and clean, it works fine, but I think most web developers will agree with me that with projects this young, small and simple, just about any framework will do.

        The differences become apparent down the line when the customers request new requirements on top of new requirements, and the site has hundreds of features. How long the frameworks let you survive the complexity is what sets frameworks apart.

        Good luck with this project, btw.

        Best regards,


        • Speedbird says:

          Thanks for the comments on the project, I’ve also have another one for you to look at, (also in bitbucket), and my god, 0 unit tests in it also….(Not surprisingly either).

          These applications are designed for “end users”, not developers, all noise is kept locally and shared with the folks that somehow have worked on it at one point in time, there is really nothing to it.

          But let me tell you the real gem here.

          Both applications took literally weeks to complete, one of the many reason that I am releasing it to the community is to show how easy it is to understand an application done in the framework, they are not extremely complex apps, but they are not hello world apps (or unfinished “proof of concepts”) either.

          I’ll give it to you, web2py is “young”, there are not many “facebooks”, or “gmails” created with it (yet), but so it was the same when Django was “young” as well.

          I fail to understand what differences on the frameworks become apparent when “requesting new requirements” etc, I’ve added many myself to my projects, including a new authorization mechanism, database structure changes (1 single file change, no DB touch-up), and financial transaction plug-in changes, with no ill effects, no hacking or otherwise.

          So let me get this straight, If someone forks web2py, run a magic-removal to remove all the global vars, eliminate exec(), make all core components explicitly importable (including request, response, -on a web application framework-) and
          what else, ah yes, create an ORM for it (web2py uses a simple data abstraction layer), then it’ll be something more worthy of pursuing, or maybe I just ignore this whole paragraph and use Django.. (back to my original point/post).



          • Speedbird says:

            Just wanted to clarify on the unit tests, while web2py’s model makes it hard to unit test a “final” application, each core component in web2py has (passed) its own unit tests, unit tests can be executed in all custom components for applications (plug-in, modules, etc) with the most notable exception of controllers, these are very important indeed! – A “wart” in the framework, agreed 100%..


    • Anthony says:


      Your points about unit testing are well taken. Unit testing is a bit trickier in web2py. However, there are solutions. First, for relatively simply tests of controller functions, you can use doctests, which web2py can run automatically either via the admin interface or the command line. For true unit testing, here are links to an overview of the web2py approach as well as a couple of existing solutions:

      Also, note that more complex apps often move much of the logic to modules (in the /modules folder), and they work as any normal Python modules (i.e., they are not part of the web2py execution environment).

      Nevertheless, your feedback is valuable, and web2py could make it easier to develop and execute unit tests.

      Regarding confusion about what’s in the global namespace and where to find things, aside from HTML helpers and form validators, web2py only injects 9 core objects into the per-request execution environment. They are not hard to track down:

      request, response, session from
      cache from
      translator from (instantiated as T)
      redirect, HTTP from
      DAL, Field from

      The rest of the web2py globals are HTML helpers (most of which have the same names as their HTML tag counterparts) and form validators (mostly of the form IS_[some condition]). They can all be found in,, and (and the LOAD helper comes from I think for most people, this does not present any difficulty.

      Some additional comments:

      > The global environment mechanism and other peculiarities in web2py, touted as features,
      > clearly create huge problem in the medium to long term, as they create all sorts of
      > difficulties interacting with other python tools and modules.

      Here you’ve gone from describing a specific problem with unit testing (which I think is solvable) to a quite broad generalization. What are the “other peculiarities”? What are the other “huge problems” and “difficulties interacting with other Python tools”?

      > This is why experienced developers look on web2py with scorn.

      No doubt *some* experienced developers look on web2py with scorn, but many of them have their own commitments to other frameworks for personal or financial reasons (not you, I know). However, there are many experienced developers who use web2py on a daily basis and think it’s great (not perfect, but great). They make a living with it. The use it for big projects that they have to maintain for a long time. Indeed, many of them are former Django users who have had a reaction quite the opposite of your own.

      web2py does do things differently from Django (and many other Python frameworks). The differences represent tradeoffs. People have different preferences regarding the tradeoffs they want to make. The design decisions web2py has made may not be to everyone’s taste, but many people (including experienced developers) do prefer web2py over Django and others.

      > I sense cognitive dissonance when I point out these problems to web2py apologists.
      > The rise to defend it, but quickly fall silent, agree with me or change the subject.

      My experience has been quite the opposite. Most people who criticize web2py have never used it and are simply repeating misconceptions about it. When their misconceptions are corrected, they are typically the ones who fall silent or change the subject. I’m not dismissing your specific concern about unit testing, but such specific critiques from actual real world users of web2py are quite rare. Most people who use it are very happy with it.

      > Only those who have made an emotional or financial investment in it are trying to hype it,
      > cos they need clients to believe in it, and they need more people to come into the small community.

      That’s a strong statement. And your evidence? No doubt that’s true of some people, but it’s equally true of some who promote Django, Pyramid, Flask, etc. But of course, most people who promote a particular framework (including web2py) do so because they genuinely like working with it.

      > Smart developers, well paid developers at big companies, especially those with interesting
      > blogs, simply aren’t using it, because they know what works and what doesn’t in the long term.

      And you know this how? Of course, Django has a much larger market share than web2py, but Django has been around a lot longer and already had a large user base and ecosystem in place by the time web2py was created. Particularly when network effects are involved, it’s always difficult for an upstart to break into an established market. I don’t think we can attribute the difference in market share purely (or even primarily) to technical differences (though some of it might be attributable to misconceptions about technical differences). In many cases, Django is chosen over other frameworks for reasons having nothing to do with its technical merits. Anyway, there are smart developers (even at big companies) who use web2py, just not as many as those who use Django. Also, note that web2py has a fairly large international user base.

      > That’s why we don’t hear about web2py.

      Well, we’re starting to hear about it more and more:

      > – globals are bad, because side effects can affect the entire system.

      Do you have an example of this causing a problem in web2py? Note, web2py creates a separate environment for each request — the environment only survives as long as the request. Separate requests are independent.

      > – exec() to load code and modules causes problems because third party tools can’t reason
      > about code coming out of exec, and odd things can happen like we may end up using multiple
      > different copies of the same code/objects.

      It’s true about some third party tools, such as with unit testing (though there are workarounds), but can you point to an example of any “odd things” happening in web2py, such as using multiple different copies of the same code/objects?

      > – implicit magic makes code harder to reason about, as it is not obvious what is happening.

      Yes, but this is simply a matter of degree. The whole point of frameworks (and high level programming languages in general) is to do some things implicitly without the developer having to explicitly code (or even know about) all the low-level details. Where you draw the line regarding explicitness in code is a matter of preference and often has to be traded off with other principles, such as “don’t repeat yourself” and “simple is better than complex.” web2py is willing to forego some explicitness in favor of productivity, but it is generally explicitness that is deemed relatively unhelpful, such as repeatedly importing the response object everywhere (even Django offers the more implicit shortcut render_to_response function in favor of more explicit response rendering code).

      Best Regards,

  • collin says:

    Noob thoughts on django vs. web2py

    First off, like other languages/frameworks, ideologies and different flavors abound. No right or wrong. I can’t stand to hear geeky arguments about this. People who have poured countless hours of love into building these tools don’t deserve it or want their proponents to engage in it.

    I have spent the past year dabbling, attempting to embrace one language and framework. PHP, ASP.Net, RoR, have all been on my radar. In fact I have just about driven myself insane weighing the merits of one over another. That is until I began learning more about Python and specifically django and web2py.

    However, when I read threads like this I find myself wavering and then second guessing the whole community, language, direction.

    I enjoyed this article and found it helpful in understanding the differences. For very experienced devs, I can fully appreciate that they know what exactly what they want and how they want it-just kindly decline the other please. On other sites I’ve read posts that can get pretty insulting.
    Repeatedly, web2py seems to be on the receiving end while people bash the source code blah,blah,blah.
    Yet, web2py’s creator generally responds to these comments with an even-handed politeness that I commend. Maybe he’s gets ugly somewhere else, I just haven’t seen it.

    From an outsider’s perspective, web2py and its creator(s) seem to have to fight to keep their head up in the python community. Not sure why when they seem to be working hard to welcome folks into python and simplify the experience of learning. That’s pythonic isn’t it?

    I’m not sure but I think devs who work with python want people to learn it. Right?? Things like wordpress, drupal, RoR take off by inviting, supporting, teaching, and having a good user experience. I know we ain’t talking PHP here, but would something like wordpress or drupal be anywhere if everyone had to work from the command line?
    This may be a testament to why something like Drupal, which IMO seems to complicate design, programming, is so successful.

    Don’t think that the same could not be true for python. I can see why Massimo created web2py the way he did. He’s a teacher but also appears to be someone who has responsibilities in the world outside of just hacking away at source code. His vision was to create something that is easy to learn with, portable and dare I say in line with how the web appears to be heading. ie. cloud service, SAAS,
    microsoft’s webmatrix, drupal, on and on and on.

    I am very interested and excited about learning both but for me, at this point as “the noob”, I’m finding web2py easier to get going with. Love the browser environment, simple deployment, portability(carry web2py on a flash drive to any pc) GUI, etc. Yet, django has some enticing features that may prove to sway me toward their camp someday.
    Who cares? this point maybe django should. I’m sure some would say django isn’t for you then. Well..we all have to start somewhere. Maybe I should just learn node.js. Hit it from the front and back.
    Ramble on..

  • Chux says:


    That is a mos beautiful comment, that mirrors much of my own thinking and experience.

    Python is beautiful .. period. Although I am a relative noob to frameworks (being a sysadmin who have used python more for CLI sysadmin work), all python frameworks I have glanced at are all great .. some better than others in what they do .. So, flame-wars are needless.

    I actually reckon Django has the most mature and complete sets of features of python frameworks. But, I fell in love with web2py’s ease of use and learning. So, I am working both of them simultaneously, as I play around with a few concepts.

    My rule of thumb (for now) is: need to knock up something quickly go with web2py .. looking at more substantial applications, where there could be need to integrate a very wide range of features, go with Django. Mind you, with Plone 4, it seems like plone is working towards easing down some of the tough entry points in plone development .. so, Plone starts to look like a good option too for larger projects.

    I say it is all great for python .. the more the merrier .. means more developers will be attracted to python, and will be spoilt for choice on frameworks to use for various projects. But I do think it will be an advantage to be proficient on more than one framework .. in the long run.

    To compete with PHP, python is screaming for CMSs and other applications that can compete with wordpress and such applications .. Let the framework choice not be an issue, and let folks work more towards those directions ..

    I like reading (in detail) these exchanges, and I learn a great deal from them .. So, a big thanks to Mike-A, Anthony, Speedbird, Brian Luft, greg.hellings , etc for sharing their thoughts ..

  • Bboy says:

    I found this website trying to decide on a framework. I am along time Python developer who has been using PHP for web projects. Now I want to use Python and web2py just makes more sense. I hear the Django guys give all these theoretical 5,000 people deep development scenarios. You know what? YouTube and Facebook were build on PHP. Old PHP, back when the default setup let you create instant variables just by passing variables on the command line. They more than survived, heck those two sites are probably more than 50% of the entire traffic on the web.

    No need to get fascist about this crap, web2py and Django both seem great and expand the population of Python users, which is great. PHP needs to go away. The point about unit test is valid; but its not like web2py is turning Python into Perl–where you can’t read your own code. It introduces a little magic to make working on the web easier. That’s fine by me.


    “Once hadst thou passions and calledst them evil. But now hast thou only thy virtues: they grew out of thy passions.” – F. Nietzsche

  • Robert says:

    Hey Greg,
    Great post, thank you. I’m new to python, migrating from PHP, and this was a very helpful read. I wanted to offer one potential observation in return. You stated: “I like the namespacing of the web2py which makes it explicitly obvious we are doing a database transaction. If only they were brought together somehow!”

    I was just reading examples on the Django site and saw some with the following syntax:
    person = Person.objects.create(name=”Ringo Starr”, group=”Beatles”)

    Perhaps that’s what you’re looking for? Given that you posted a year ago, you probably know this by now, but I thought maybe it was a helpful mention.

    • Hkon says:

      Actually, you don’t need to call the save() method if you’re not making changes to the object after calling the model manager’s create(); create already tries to insert a new row into the requisite DB tables.

  • [...] Not so with web2py. I soon found out why it had been so difficult for them; because web2py code has the global environment, it has to expect the global environment, so any code that is run by unit tests must inject that global environment, which is actually really hard to do. So hard that it took me (an experienced python developer) a entire weekend to write a web2py nose plugin just so that I could run unit tests with nose. It would normally take about a minute to get cracking with nose: install it, type “nosetests”. [...]

  • Danpe says:

    Btw, web2py support many-to-many relationship:

    But the big advantage of Django is that the community is larger.

  • Leave a Reply