t-strings have been merged into Python 3.14 for its beta 1 release (May 7).
Since reading the PEP and its associated example repo, I’ve been noodling about how Django could use t-strings. I am sure others are eager to think about this too. Here are some ideas, I wonder what everyone else thinks.
1. format_html()
and format_html_join()
Extend format_html()
and format_html_join()
to support t-string templates:
from django.utils.html import format_html
format_html(t"Hello <strong>{user.name}</strong>")
This would be a natural extension to these functions. The t-string example in the Python documentation shows a theoretical html
function, but provides no implementation. I think it makes sense that we’d make Django’s existing tool support this new syntax.
The documentation does show an “advanced” use case, where a t-string detects a dict argument and expands that into HTML atttributes:
attributes = {"src": "shrubbery.jpg", "alt": "looks nice"}
template = t"<img {attributes}>"
assert html(template) == '<img src="shrubbery.jpg" alt="looks nice" class="looks-nice">'
I’m not sure what others think, but I am cautious about playing with such features in Django, especially the pre-existing format_html()
. We can leave the experimentation to other t-string-powered HTML packages. I think supporting the most basic use cases only is sufficient for format_html()
: after all, if you want more complexity, you can reach for Django templates.
One note: Previously, we deprecated calling format_html()
with one argument, because developers would often put an f-string there without correct escaping (blog post). Adding t-string to suport to format_html()
would require us to allow a single-argument form but only if the given argument is a t-string Template
.
2. Raw SQL
There are various ways to run raw SQL in Django:
It would be neat if we could support t-strings in these cases too, like:
with connection.cursor() as cursor:
cursor.execute(t"SELECT * FROM example_book WHERE id = {id}")
I think we could use a simple implementation where we transform templated variables to placeholders, and store variables in a tuple, making the above example equivalent to:
cursor.execute("SELECT * FROM example_book WHERE id = %s", (id,))
I can see one risk here, which is that if the DB-API ends up being extended to support t-strings with some different interface, we might not be able to support that.
Those are the ideas I’ve thought about. Any other suggestions? Maybe translations?