Thoughts from DjangoCon Europe
DjangoCon Europe
A bit of a roundup post this month. I wanted to talk about the recent DjangoCon Europe, and the reactions coming out of that.
Athens & the Conference
In the first place, the conference was amazing. Over three-hundred people in person, and a good number of online attendees. A great venue, with a good auditorium, in a nice location. Athens itself was very walkable.
I travelled a day early, and so had time to explore. I thought I’d play tourist, and decided to go up the Acropolis. It was €30 entry, which was fine — it all goes to the maintenance — but I remember thinking that it probably wouldn’t be that good.
When I got to the top, I did have to grant “Well played, Athens!”

I was there early, went straight to the top and explored my way down. It’s quite spectacular.
As I exited, across the way, is a park containing the (supposed) prison of Socrates. As a philosophy graduate it’s quite something to see. I sat on a bench with Free Palestine graffiti pondering, before moving on.
The next morning, I was giving the opening talk of the conference, so left my flatmates early to walk to the venue alone. Next to the venue was the archeological site of Aristotle’s Lyceum, the school he founded in Athens. Aristotle has great importance to me — philosophy is a dialogue, so it makes no real sense, but if we played Who’s your favourite?, I’d likely say Aristotle, Hume, and Kant, which we can chat about one day if you like — and to be in this place, with these sites, of this significance is something that I found deeply touching.
The Talks
The talk line up was really solid for all three days. I helped on the program committee by reviewing every one of the 100+ (I can’t recall the exact number, but well over 100) proposals. Narrowing down was not easy, but I think the team made a great final selection.
Do watch out for the videos when they make it to YouTube.
I’m going to pick three talks, one from each day, to mention:
- Day 1: Paolo talked about AI-assisted contributions and maintainer load. This is something I’ve been thinking about a lot. Paolo argued that AI amplifies both the existing problems and possibilities, and I think that’s dead right. For at least as long as I’ve been doing it, we’ve talked about maintainer load, and burnout, and entitled demands from users, and extractive contributions. (That list just focusing on the negative.) AI ramps this up: it’s not new.
- Day 2: Gergő Simonyi talked about Role-based access control in Django, and how they forked Django Guardian at authentik, to implement generic role-based access control. This is one of those perennial topics in Django. Basically because we don’t have a standard solution every project (including mine) ends up implementing their own. This was the talk that gave me the biggest OK, let’s dig into this bit of homework.
- Day 3: Charlie Denton and Sam Searles-Bryant, from the Kraken team, talked about transaction handling in Django, and introduced their package django-subatomic, which gives better control over transactions, and makes the testing story there a lot easier. django-subatomic has reached a 1.0 milestone, signifying that they think it’s stable enough to generally recommend, and (whilst there are questions to be answered) I’m quietly hopeful that this can make its way to Django itself.
Now, I could have mentioned plenty of other talks there. I’m still tempted to, but I will resist. The whole schedule was great, is all I can really repeat.
Sprints
I was there for the first day of the sprints. We had a big office, kindly offered by Django shop Bespot. It was packed, almost standing room only.
I got a great session in on Neapolitan with Dennis Stritzke, and with Andrew Northall injecting lots of energy, he, Paolo and I made good progress on Django on the Med 🏖️

Django on the Med is back in Pescara Italy on September 23-25 2026 — we’ll see you there!
Overall
It was awesome! I take my hat off to the organising team. They really did put on a great conference. 👏🎩❤️
If you fancy Athens, PyCon Greece is back there in the Autumn
Static Islands, Dynamic Sea
I was honoured to be invited to keynote at DjangoCon Europe. I gave my talk Static Islands, Dynamic Sea, which is about Django’s dynamic core, which I take to be inescapable, and how we can build with statically typed pure Python classes on top of that, usingDjango-Mantle.
The video isn’t available yet, but it was a longer version of the talk I gave at the JetBrain PyTV Unplugged event earlier in the year, which has a good Q&A discussion with Will Vincent after it, and if you watch that, combined with reading last month’s essay on Decoupling Your Business Logic From the Django ORM, you’re not far off what I talked about. (The keynote edition includes the discussion of where the Active Record pattern starts to break down, and some thoughts on DRF and Django’s REST story going forwards.)
The response was good. Lots of people were interested in the ideas, and I don’t think anyone thought I was totally mad, which is kind of the litmus test.
If you’re not up to speed, go watch the video and read last month’s essay. I just want to focus here on three different points that were raised in different ways, in conversations during the conference, and since.
The first point I call, let’s actually type it.
The whole point of the Dynamic sea part of the talk is that Django is built on dynamic patterns. It’s dynamic by design. From Django’s design philosophies:
Django should take full advantage of Python’s dynamic capabilities
My conjecture is that it’s a fools errand to try and retrofit static typing onto patterns which can’t be expressed in Python’s type system, which was the point of the mypy quote I included.
Now, the point is, that’s only a conjecture. I’m totally open to the possibility that a suitably herculean effort might show that it is possible, and if so, we can see where we go from there. (But I don’t assign it a high likelihood, and I think our time is better spent elsewhere. Hence the approach I do adopt.)
More though, I think dynamic patterns are powerful. They enable the powerful and flexible APIs that we’re used to. That mypy point again. Given that Python is a dynamic language, and has to pay the performance penalties for being so, I really do question what Python can still offer, in contrast to (actual) static languages, if we’re not going to lean into one of it’s main sources of power.
To wit, I want to double down on the point that the dynamic sea is something we should embrace, and not try to avoid. I think that’s something that’s been lost in the recent debate. (I was talking with Jacob Walls one evening about what talks I’d like to see going forward: one topic exactly was about us relearning, maybe, what Python’s meta-programming tools really bring to the table.
The second point, then, is concerns about mapping between model classes and Mantle shapes specifically.
Say I have my Bookmark model, and then my BookmarkData shape class, as I change the fields on the model, I’ll need to propagate those to the shape class, and it becomes a maintenance burden. How do we keep those in sync?
Well, yes.
This is just/precisely/exactly/… the issue that arrises from moving away from the active record pattern to a separate domain model. As soon as you do that, then you’ve got layers, and you need to keep them in sync. That’s the cost.
The benefit is the better decoupling, and so on, that moving to a separate domain layer gives you.
But if keeping your layers in sync is your biggest problem, then perhaps you’ve made the move too early. You’re probably over engineering if that’s the case.
Let me point you to Harry Percival’s post So Many Layers! A Note of Caution on the Cosmic Python site. If you don’t know it, this is the site for the Architecture Patterns in Python book, which is the (my paraphrase) doing architecture in Python right book, and of which Harry is the author. It’s absolutely worth your time, and you can buy it to support the work, or read it free on the site if you prefer.
In the post, Harry describes our problem here (of changing a field):
If you’re using a framework like Django, you might be used to thinking of a change like this, in a perfect world, as a change you can make to just one file. You would change models.py, and then your ModelForm will be updated automatically, and maybe even the frontend will “just work” too, if you’re using the form’s autogenerated HTML. That’s one of the reasons that Django is so good as a rapid application development framework: by closely coupling its various parts, it saves you a lot of messing about with database tables, html forms, validation, and so on. And if those are the main things you spend your time on, then Django is going to save you a lot of time.
But where we’ve got to, our Bookmark model has grown too much. It’s become unwieldy. The benefits of having everything in one place has become overwhelmed by the difficulty of keeping the separate threads of our logic under control. This was precisely why we introduced the separate Mantle layer.
So in Harry’s case, he’s gone much further:
So that’s fifteen files. Fifteen! To add one field!
He has a lot of layers, maybe too many, and in fairness admits so in a footnote:
OK, in theory. In practice, I think this particular app was a little overengineered.
Since we’ve got a Greek theme, our challenge is to navigate between the Scilla of tight-coupling and the Charybdis of over-engineering. How exactly you structure your application will depend on where you’re at. If you dive straight into the complex patterns you’ll slow yourself down just as surely as if you cling to the simpler ones for too long.
For Mantle, if the costs of keeping shape classes in sync with the models they’re structuring outweighs their benefit, then obviously stick with your fat models. Fat models can go an awful long way. (This is why, despite all the criticisms from the purists, Django remains and has remained so popular a choice all these years.)
But in the same breath, the problems I described with the active record pattern as your models grow are real. You’ve felt them. And it’s then, for you to decide, when bringing in Mantle to decouple your logic from the model class is worth while.
No it’s not cost free. Of course not. We’re engineers. Nothing ever is. It’s about the trade-offs we make, and when. That’s the value we bring.
The third (and final) point then was about overrides.
Let me give you a simple example from the Mantle docs:
from attrs import define
from django_readers import qs
from mantle import overrides
@overrides(
{"file": (qs.include_fields("file"), lambda a: a.file.name)}
)
@define
class Attachment:
id: int
name: str
file: str # Django file.name relative to media root
We’ve got an attachment model and need to map from the file field to a path relative to our media root directory.
The concern here is that overrides are about how we query from the ORM, and yet they’re attached to the individual shape classes, which (back in architecture mode) should be totally pure Python classes without any extras. Shouldn’t overrides be part of the Query layer?
And yep, absolutely. But pragmatism beat purity here.
The issue is that shape classes can be arbitrarily nested.
Let’s say we want to fetch a tree that looks like this:
Bookmark -> Note -> Attachment
A bookmark has a note which has attachments.
If we were to query specifying overrides there, it would look something like this:
Query(Bookmark.objects.all(), BookmarkData, overrides=...)
Where the challenge is, how on earth do we manage the overrides keyword argument where we need to pass overrides for the nested shapes?
I’m not precluding that some API is available there, but I’ve spent a long time working with variations on this problem, and keeping overrides local to the shape class is the cleanest and most maintainable I’ve found. You define your shape class and can include it on any parent shape, without that parent needing to know any of the details of how the mapping of its child looks.
The shape classes are just your plain Python classes. We merely tag on this one piece of private metadata, that your code never interacts with, and that enables the flexibility that you need in the ORM mapping. (Write a few. See how you get on. It’s fine.)
DEP 20: Annual Release Cycle for Django
You may recall my An Annual Release Cycle for Django essay from last year.
I finally got round to proposing it as a formal DEP:
Adopt Annual Release Cycle (DEP 20) by carltongibson · Pull Request #109 · Django/Deps
The feedback has been constructive. What’s pleasing is that there a general agreement on the core of the issues about improving the Python version support and dropping the gap between LTS version. The conversation points have all been about the details, which are important, but which aren’t existential. We can all live with which ever way we go on those. That’s positive. Do go give that a 👍 if you’re keen to see us push this through.