5 big and powerful Python web frameworks

5 big and powerful Python web frameworks

Why build your own user credentialing, form handling, security, and other stock components? These big and powerful Python frameworks cover all the bases

Credit: Dreamstime

When you build a back end for a website or service, even one that seems modest at first glance, you may quickly find it’s anything but. Even a “simple” site turns out to be a hive of complexity. User management, data design, form submissions, security,—implementing all of that by hand gets tedious.

For those big web projects, when you know you will need everything plus the kitchen sink, it’s best to turn to a framework that comes with batteries (and chargers) included. Here are five heavyweight web frameworks for Python that come with all you need to build robust web applications and then some.


CubicWeb is billed as “a semantic web application framework that favours reuse and object-oriented design.” It’s an intriguing system—as noted by Rick Grehan when he reviewed it for InfoWorld back in 2011—that emphasises the use of abstractions and reusable building blocks of code called “cubes.”

In fact, CubicWeb might be too abstract or idiosyncratic for some developers, and its development speed and feature set lag other frameworks.

Cubes are software components that feature a schema (data model), entities (programming logic), and views. By assembling multiple cubes, each performing its own task, you can compose software applications by reusing your own code and the code of others.

At its core, CubicWeb provides basic scaffolding used by every web app: a “repository” for data connections and storage; a “web engine” for basic HTTP request/response and CRUD actions; and a schema for modelling data. All of this is described in Python class definitions.

To set up and manage instances of CubicWeb, you work with a command-line tool similar to the one used for Django. A built-in templating system lets you programmatically generate HTML output. You can also use a cube that provides tools for web UIs, such as that for the Bootstrap HTML framework.

Although CubicWeb supports Python 3 (since version 3.23), it does not appear to use Python 3’s native async functionality.

A roundabout way to include async would be to use the cubicweb.pyramid module to use the Pyramid framework as the web server, and draw on a fork of Pyramid that uses async constructions. It’s also possible to perform tasks asynchronously with the cubicweb-worker cube. But anything more straightforward seems out of reach for now.

To fetch or manipulate persistent data in a CubicWeb app, you use Relation Query Language (RQL), which employs vaguely SQL-like syntax but is patterned after the W3C’s SparQL. CubicWeb’s justification for this is, again, abstraction: RQL provides a highly decoupled route to interrelate various data sources.

Because CubicWeb has a lot of dependencies, it’s best to use pip install to fetch them all. You may also have to perform a certain amount of manual tweaking on the local environment. This is in contrast to other frameworks where running pip install or dropping the framework’s code into a subfolder of another project is all that’s required. Or you could use a Docker container to get things running.

CubicWeb refers to its lengthy documentation as “the book.” The authors of the book have taken the time to explain CubicWeb’s unusual approach, demonstrate how to build some basic applications, include API references, and in general go out of their way to be specific.

CubicWeb remains under active, if slow, development. Plans for CubicWeb 4.0 have been mulled since 2012, but no timeline has yet been offered for delivering it.


In the decade and change since Django first appeared, it has become one of Python’s most widely deployed frameworks for creating web applications. Django comes with most every battery you might need, making it more suitable for building big applications than small ones.

Django spent many years sitting at version 1.x. When Django 2.0 arrived in late 2017, it dropped compatibility with Python 2 in favor of Python 3.4 and up. Django 3.0, released in December 2019, requires Python 3.6 or better, and adds support for the new asynchronous ASGI standard for Python web applications.

A key part of Django’s appeal is deployment speed. Because Django includes so many pieces you need for developing the average web application, you can get moving quickly. Routing, URL parsing, database connectivity including an ORM (object-relational mapper), form validation, attack protections, and templating are all built-in.

You’ll find building blocks for most common web application scenarios. User management, for instance, is found on most websites, so Django offers it as a standard element.

Instead of having to create your own system for tracking user accounts, sessions, passwords, log-ins/log-outs, admin permissions, and so on, Django provides those features natively. They can be used as-is or extended to encompass new use cases with minimal work.

Django has sane and safe defaults that help shield your web application from attack. When you place a variable in a page template, such as a string with HTML or JavaScript, the contents are not rendered literally unless you explicitly designate the instance of the variable as safe.

This by itself eliminates many common cross-site scripting issues. If you want to perform form validation, you can use everything from simple CSRF protection to full-blown field-by-field validation mechanisms that return detailed error feedback.

A feature set as rich and broad as Django’s wouldn’t be much good without robust documentation to go with it. The Django documentation drills into every aspect of the framework from multiple angles. Working with Python 3 or other flavours of the language, doing security right, implementing common web application components (like sessions or pagination), generating sitemaps—they’re all covered. The APIs for each layer of the application—model, view, and template—are described in detail as well.

With great power, however, comes great complexity. Django applications have a reputation for being top-heavy, fraught with many moving parts. Even a simple Django app requires a fair amount of configuration to get running. If your goal is to do little more than set up a couple of simple REST endpoints, Django is almost certainly overkill.

Django also has its quirks. For instance, page templates cannot use callables. Example: You can pass {{}} as a component in a template, but not {{user.get_name()}}. It’s one of the ways Django ensures templates don’t inadvertently shoot you in the foot, but those constraints can be jarring if you’re not prepared for them. While there are workarounds, they tend to take a toll on performance.

As of version 3.0, Django has added support for asynchronous views. Unfortunately, there isn’t yet support for async in other parts of the Django stack, like the ORM. But you can deploy Django using ASGI to take full advantage of async views.


In the world of Ruby programming, Ruby on Rails is the de facto web framework. DePaul University computer science professor Massimo Di Pierro was inspired by Rails to create a web framework in Python that was similarly easy to set up and use. The result is Web2py.

Web2py’s biggest attraction is its built-in development environment. When you set up an instance of Web2py, you’re provided with a web interface, essentially an online Python application editor, where you can configure the app’s components.

This typically means creating models, views, and controllers, each described via Python modules or HTML templates. A few example apps come with Web2py out of the box. You can take those apart to see how they work or leverage them as starter templates to create your own apps.

Developers typically deploy Web2py by downloading its source code and building on that. But for less technical users on Windows or MacOS, Web2py’s creators offer versions that are essentially standalone servers. Download, unpack, and run one of these versions, and you’ll have a local web server with a preconfigured copy of Web2py built-in. This is a nice way to get a leg up on creating a Web2py app, which can then be deployed elsewhere as needed.

Web2py’s web interface was built with Bootstrap 4, so it’s easy on the eyes and easy to navigate. The in-browser editor is no substitute for a full-blown IDE, but it’s outfitted with helpful aids like line numbering and Python syntax highlighting (including auto-indentation). Also included is a quick web interface to the Python shell, so you can interact with Web2py from the command line—a nice concession to experts.

The data abstraction system used in Web2py works a little differently from Django’s ORM and other ORMs inspired by it (such as Peewee). Those systems use Python classes to define models, whereas Web2py uses constructor functions like define_table to instantiate models.

The differences are likely to be jarring only if you’re used to the other way; they shouldn’t faze newcomers. You’re not likely to have any trouble with hitching Web2py to a data provider, as it talks to nearly every major database in existence.

A truly useful database-related function in Web2py is the ability to generate a diagram of the models, allowing you to visualise how your models relate to each other. You will need to install the PyGraphviz library to enable that feature, though.

Web2py supplies many other professional-grade components: internationalisation functions, multiple caching methods, access control and authorisation, and even front-end effects (for example, a date picker in forms) via integrated support for jQuery and AJAX.

Hooks for external and internal middleware are also included, although you aren’t allowed to use middleware to replace core Web2py functions. However, there’s as yet no explicit use of Python’s async functionality in Web2py, although there is a scheduler for handling long-running tasks. 

It’s no wonder that Web2py’s documentation is referred to as “the book.” First, it covers a staggering amount of material on Web2py, Python, and the deployment environments used for both. Second, it’s written in a highly accessible, narrative style. Third, it talks in-depth about common application-building scenarios. There’s an entire chapter, for instance, on using jQuery to build AJAX applications.


Weppy feels like a halfway mark between the minimal simplicity of Flask and the completeness of Django. While developing a Weppy app has the straightforwardness of Flash, Weppy comes with many features found in Django, like data layers and authentication. Thus, Weppy is suited to apps that range from extremely simple to modestly sophisticated.

At first glance, Weppy code looks a great deal like Flask code or Bottle code. Few instructions are needed to get a basic, single-route website up and running.

Routes can be described through function decorators (the easy way) or programmatically, and the syntax for doing so hews closely to Flask/Bottle. Templating works about the same, aside from minor variations in syntax.

Weppy contrasts with those smaller frameworks by including some features they incorporate only as plug-ins or add-ons. For instance, neither Flask nor Bottle has a built-in ORM or a data management system. Weppy includes an ORM, albeit one based on the pyDAL project rather than the far more popular SQLAlchemy.

Weppy even supports schema migrations, which Django supports as part of its ORM (Django’s migration system is also a great deal more automated). While Weppy has an extension mechanism, the list of officially approved add-ons is tiny, far smaller than the catalog of extensions for Flask.

Lighter-weight frameworks like Weppy are often used to build RESTful APIs, and Weppy comes outfitted with convenience functions for that purpose. Put a @service decorator on a route, and the data you return is automatically formatted in your choice of JSON or XML.

Weppy includes other features that seem more in line with a larger framework, but are implemented without bulk. Examples include data validation mechanisms, form handling, response caching, and user validation. In all of these cases, Weppy takes a “just enough” approach.

The features provided aren’t as complete as you might find in Django and other heavyweight frameworks, but a developer doesn’t need to invest a lot of work in making them useful, and they can always be extended after the fact.

Another heavyweight framework feature found in Weppy is internationalisation support. Strings in templates can be translated according to locale files provided with the application, which are simple Python dictionaries. The choice of language can also be set by parsing the browser request (that is, the Accept-Language HTTP header) or by binding a translation to a specific route.

Weppy’s documentation has the same flavour as the framework itself. It’s clean, readable, and written to be consumed by humans. Aside from the usual “hello world” example, it includes a nice walkthrough tutorial that lets you create a microblogging system as a starter project.

Long-term plans for Weppy include supporting async and sockets as low-level, first-class entities. Weppy’s developers plan to introduce those features in version 2.0, and then to require Python 3.7 or better for all future versions of Weppy.


Zope is not for simple RESTful APIs (per Bottle or Flask) or even basic websites with interactivity (à la Django). Rather, Zope is meant to be a full-blown, enterprise-grade application server stack, similar to server offerings for Java.

The documentation describes the framework as “most useful for component developers, integrators, and web designers.” One major third-party product, the Plone CMS, uses Zope as its substrate and serves as a major driver of Zope’s continued development.

Zope works by taking requests from the web, matching the parameters of the request against an internal object database (ZODB), and executing that object using the request’s GET or POST parameters.

Whatever comes back from the object is returned to the client. Zope uses this database-object system to simplify tasks like assigning granular object permissions, providing inheritance hierarchies for objects, and handling transactions and rollbacks for database objects.

Because of Zope’s size and complexity, installation requires some work; it’s not a matter of simply unpacking the source into a project subfolder. Zope uses a specialised setup tool, zc.buildout, that installs a copy of the Zope source distribution according to a config file. Anyone who uses Python’s package magament system will flinch.

When you fire up Zope and connect to the server, you’ll be greeted with a web UI, where you can create and edit ZODB objects. Objects take one of three basic roles—content, logic, and presentation—and can consist of documents (basically, any file with a MIME type), Python scripts, and HTML templates.

Templates can be handled using the new and more flexible Zope Page Templates (ZPT) system, or the older and more basic DTML markup system. ZPT uses properties within HTML tags to indicate where to place data, making it easier to design templates using conventional HTML tools. But the ZPT syntax takes some getting used to.

One of the advantages Zope claims for its object-oriented methodology is that every action in the system, no matter what sort of object it acts on, is encapsulated by a transaction. Thus, if you delete a file stored in Zope’s database or make a destructive change to a piece of code, you need only roll back the action that performed it.

The downside of Zope’s approach is that it’s hard to use modern source-control tools like Git on such a codebase, and it means you’re putting the data at the mercy of Zope’s custom database tools. Note that you can connect an external database like MySQL to a Zope application, but that’s strictly for hosting application data, not for replacing the ZODB.

Another downside to Zope, at least in its current form, is no direct support for Python’s async syntax. However, the zc.async package allows you to distribute tasks across machines and synchronise them in a ZODB instance.

Tags python


Show Comments