Django, the Python web framework with all batteries included, is on the verge of its fifth major release. Here’s a rundown of five big new Django 5 features to take advantage of, in both existing and new Django projects.
Top 5 new features in Django 5
- Form fields are simpler to render
- Model fields for computations and generated columns
- Field choices are easier to write
- More async view decorators
- Exception handling for async disconnects
1. Form fields are simpler to render
Form fields in Django have several elements—descriptive label, help text, error label, and the field itself. If you have a form with multiple such fields, laying them out manually can get tedious.
To remedy that, Django 5 offers a new field group method for form fields. When used in a template, the .as_field_group
method renders all the elements in the field group automatically, according to a template you can customize.
With field groups, you can render all this:
{{ form.username.label_tag }}
{% if form.username.help_text %}
<div class="helptext" id="{{ form.username.auto_id }}_helptext">
{{ form.username.help_text|safe }}
</div>
{% endif %}
{{ form.username.errors }}
{{ form.username }}
… as just this:
{{ form.name.as_field_group }}
Again, the presentation is customizable—you can replace the default template for field groups application-wide, or you can customize it per-field or even per-request.
2. Model fields for computations and generated columns
Computed columns in databases let you define the value for the column as the output of some formula, which is computed on the database before being sent to the client.
Django 5 now lets you define fields in models with a database default parameter, which lets you provide a database-computed default value. For instance, a DateTimeField
could use Now()
as a default.
Note that db_default
can only be set to something that’s the output of a combination of literals and supported database functions.
Another handy Django 5.0 addition in this vein is GeneratedField—a new field type whose value is always generated from the values of other fields. The results can either be stored in the database when the row is written or updated (a “stored” field), or computed only when the row is read (a “virtual” field).
Also note that GeneratedField
s can only use other fields within the same model as inputs. You also can’t use other generated fields as a source, only actual fields.
3. Field choices are easier to write
In previous versions of Django, when you wanted to list the choices available to Field.choices
and ChoiceField.choices
objects, you had to construct an ungainly arrangement of 2-tuples or Enumeration
subclasses:
HQ_LOCATIONS = [
("United States", [("nyc", "New York"), ("la", "Los Angeles")]),
("Japan", [("tokyo", "Tokyo"), ("osaka", "Osaka")]),
("virtual", "Anywhere"),
]
With Django 5, you can use a much more succinct declaration using dictionary mappings:
HQ_LOCATIONS = {
"United States": {"nyc": "New York", "la": "Los Angeles"},
"Japan": {"tokyo": "Tokyo", "osaka": "Osaka"},
"virtual": "Anywhere",
}
This makes choices easier to encode as literals, and a little easier to generate programatically, too.
4. Many more async view decorators
Django added its first support for Python’s asynchronous mechanisms in 3.0, but not every part of Django gained async support from the beginning. It’s been added in layers, with support for async views added in 4.0, and support for the ORM coming in a future release.
Because Django has been adding async support gradually, many decorators previously didn’t support wrapping async views. That changes with version 5, wherein many more decorators can now wrap async views. Among the most useful are the ones that ensure CSRF (cross-site request forgery) protection to views.
5. Exception handling for async disconnects
With async connections, there’s always the risk that a long-held connection will be closed before Django returns a response. Previously, there was no built-in mechanism to handle cleanup when an async connection was canceled. Django 5 raises an appropriate exception, asyncio.CancelledError
, which you can trap as needed.