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
CubicWeb is billed as “a semantic web application framework that favors 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 emphasizes 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 modeling 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.
Django
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 flavors 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 {{user.name}}
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.
Web2py
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 visualize 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: internationalization functions, multiple caching methods, access control and authorization, 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
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 internationalization 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 flavor 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.