24 Jul 2026

feedDjango community aggregator: Community blog posts

Issue 347: Django 6.1 release candidate 1 released

News

Django 6.1 release candidate 1 released

This is the final opportunity to try out the new version before Django 6.1 is released. Try it, run your test suite, and report anything that breaks!

The DjangoCon US 2026 schedule has been released!

The talk lineup is out, covering Django 6.0 and 6.1 features, modern deployment patterns, GeoDjango at scale, and lightning talks across all three days.

PyPI Releases now reject new files after 14 days

PyPI will reject new files uploaded to releases older than 14 days to limit the impact of compromised publishing tokens or workflows.

Planned Updates to the PyPI User Interface

PyPI's first UI refresh since 2018 will roll out in phases over the coming months, surfacing more security signals on package pages. The first phase is staged on TestPyPI now and ready for your feedback.


Wagtail CMS News

What our AI guiding principles actually mean

Wagtail unpacks its refreshed AI guiding principles and how they steer adoption in practice, starting with a firm commitment: no AI dependency in Wagtail core, with AI features staying opt-in through packages like Wagtail AI.


Django Software Foundation

DSF Board monthly meeting, July 09, 2026

Minutes from this month's DSF Board meeting: a host for DjangoCon Europe 2027 was approved, a new Google Summer of Code Working Group was chartered, Executive Director hiring continues with guidance from the PSF, and grants went to PyCon Cameroon and PyCon Africa.


Updates to Django

Today, "Updates to Django" is presented by Raffaella from Djangonaut Space! 🚀

Last week we had 17 pull requests merged into Django by 11 different contributors - including 6 first-time contributors! Congratulations to Tom Most, CharulL00, Sina Chaichi Maleki, Harvey Bellini, Stephanie and Vismay for having their first commits merged into Django - welcome on board!

News in Django 6.2:

Thanks to the continuous efforts of the contributors, a SQLite regression test has also been added to inspectdb when a table has a foreign key that references sqlite_master. (#25243)

Support for prefers-color-scheme was also implemented, adding dark mode CSS overrides for the technical 500 (traceback) and 404 debug views. (#35875)


Django Fellow Reports

Django Fellow Report - Natalia

A security-heavy week: two patches for confirmed vulnerabilities, deep-dive reviews of two more, and prep for the August release with CVE metadata and prenotifications, plus continued iteration on EmailValidator improvements.

Django Fellow Report - Sarah

Reviews across Django and djangoproject.com, including the Selenium to Playwright migration and admin widget fixes, plus a new GitHub Action to test djangoproject.com against Django main and engagement on six security issues across Django and djangoproject.com.

Django Fellow Report - Jacob

Sustained attention on a couple of security reports, alongside triage and a long review list covering dark mode error pages, Oracle Test Pilot in CI, and the asgiref 3.12 update that enables free-threading tests.


Python Software Foundation

Get Ready: PSF Board Nominations Opening Soon!

PSF Board nominations open July 28, with voting September 1-15. If you're a voting member, affirm your intent to vote by August 25.

Get Ready: 2026 Python Packaging Council Nominations Opening Soon!

Nominations for the first-ever Python Packaging Council open July 28 and close August 11.


Events

Django Girls Chicago - August 22, 2026

Django Girls returns the Saturday before DjangoCon US in Chicago: build your first website, eat free food, and meet fellow aspiring Django developers. The free workshop is limited to 45 people and applications close August 12, so apply early.

Preparing for sprints as a project leader (at DjangoCon US)

As DjangoCon US approaches in just a few weeks time, here are some good tips on how to make the most out of the sprints following the tutorial talks.

A First-Timer's Guide to Navigating America

If you are attending DjangoCon US, please do follow the news section of the website, as it has helpful articles like this one, as well as info on childcare at the conference, and more.


Sponsored Link

When is it worth paying for a mentor?

Thinking about hiring a mentor to grow as a Django developer? Here are a few honest questions to help you get clarity on whether now's the right time.


Articles

Django: introducing django-crawl

Adam Johnson introduces django-crawl, a new package that crawls your whole site with Django's test client (via links, sitemaps, or a Python API) to surface broken pages before your users do.

Nifty Django Feature: Form Templates

Django's form templates separate a form's HTML from the view that processes it: set template_name on the form for one reusable layout, or on an individual field when a single input needs custom markup.

Some more things about Django I've been enjoying

Building a "2010 style" backend-heavy web app, this writeup highlights Django's readable query builders, handy template filters like querystring and json_script, and the comfort of automatic migrations. It also covers the author's practical performance questions, including a misconfigured cached template loader and why it mattered.

Browser Push Notifications for a Django Website

A step-by-step tutorial on adding browser Web Push notifications to a Django site using VAPID keys, a service worker, and a Huey background task, so you get OS-level notifications even when the admin tab is closed.

Is it time to go back to Django?

Some arguments for Django's opinionated, batteries-included approach in the AI-coding era, since it limits the decisions an AI agent has to make and reduces the chance of it going astray.

Deploying Web Apps in 2026: My EuroPython Conference Talk

The written version of Will Vincent's EuroPython talk, which maps today's hosting landscape and builds a ten-step mental model of everything your dev server quietly handles for you, from WSGI servers and static files to running migrations at release time.

My EuroPython 2026 - Paolo Melchiorre

A day-by-day recap of Paolo Melchiorre's EuroPython 2026 in Kraków, compiled from Mastodon posts and photos, from the Python Steering Council update to rethinking asyncio for free-threaded Python and time with the Django community at the booth.

EuroPython 2026 Recap - Will Vincent

Highlights from a packed week in Kraków, where the standout theme was agentic AI workflows, with teams split between off-the-shelf tools and heavy internal tooling.

PyCon US 2026 Recap - Katherine Michel

Katherine's famous PyCon recap is here! Security and AI front and center, PSF and PyPI updates, steering council priorities for free-threading, and lots of great pictures.


Events

Django on the Med

Three days of Django development sprints, September 23-25 in Pescara, Italy. The second edition is free to attend and gathers Fellows, board and Steering Council members, and contributors new and experienced to push Django forward.

Django Day Copenhagen 2026

October 2 in Copenhagen. The first three talks are by Marijke Luttekes, Efe Öge, and Denny Biasiolli.


Django Job Board

Three new remote openings join the board this week, from AI-native full-stack work at Hive Collective to Django backend engineering for genetic testing at MyOme and Python + TypeScript roles at Fusionbox.

Senior Full Stack Engineer at Hive Collective 🆕

Senior Backend Engineer at MyOme 🆕

Python + TypeScript Engineers at Fusionbox 🆕

Freelance Full-Stack Web App Developer at Mindrift


Projects

adamchainz/django-crawl

An in-process site crawler using Django's test client.

FROWNINGdev/django-orm-lens

See your entire Django schema (every model, field, and relationship) in your editor, terminal, or AI agent, one keystroke away from a live ER diagram.

24 Jul 2026 3:00pm GMT

Django: release code words up to 6.1

Did you know that each Django release has a "code word" associated with it? It's hidden in plain sight, in the announcement blog post describing the list of features coming in the next version. I think this is a lovely little tradition.

I last covered the list back in 2021, for Django 3.2 (post). This post expands the table up until Django 6.1, which is expected next month (the first release candidate came out earlier this week).

Each code word links to its Wiktionary entry so you can see the definition. The word frequency column is based on the English data in the wordfreq Python package, as occurrences per billion words, so higher numbers mean the word is more common.

Version Post author Quote with code word highlighted Word frequency
(per billion words)
1.7 James Bennett ...will bring several major new features to Django, along with a host of other improvements... 58,900
1.8 Tim Graham ...several major new features and a cornucopia of other improvements... 363
1.9 Tim Graham ... myriad of goodies... 3,090
1.10 Tim Graham ... panoply of new features... 209
1.11 Tim Graham ... medley of new features... 1,910
2.0 Tim Graham ... assortment of new features... 1,820
2.1 Tim Graham ... smorgasbord of new features... 263
2.2 Carlton Gibson ... salmagundi of new features... 36
3.0 Carlton Gibson ... raft of new features... 2,880
3.1 Mariusz Felisiak ... potpourri of new features... 245
3.2 Carlton Gibson ... mezcla of new features... N/A (not in English data)
4.0 Mariusz Felisiak ... abundance of new features... 7,240
4.1 Carlton Gibson ... profusion of new features... 331
4.2 Mariusz Felisiak ... farrago of new features... 83
5.0 Natalia Bidart ... deluge of exciting new features... 1,120
5.1 Natalia Bidart ... kaleidoscope of improvements... 692
5.2 Sarah Boyce ... composite of new features... 8,710
6.0 Natalia Bidart ...assembles a mosaic of modern tools and thoughtful design... 3,800
6.1 Jacob Walls ...a harmonious mélange of new features... 98

Some observations on the newer entries:

Fin

May you enjoy Django's ever-growing omnium-gatherum of features,

-Adam

24 Jul 2026 4:00am GMT

22 Jul 2026

feedDjango community aggregator: Community blog posts

Tracking Blips

bliptracker was a side project that I happened to produce during June and last week realised I hadn't written about it here, so here goes!

One annoyance I have with Claude.ai (or other web based LLM interfaces), is that I would start multiple conversations across multiple topics such as client work, organising my Todoist, an idea to explore, gifts to research, the list goes on, but I was keeping open tabs for each conversation to not lose track of the active conversations, but this didn't work as I still had those open loops in my head to follow up to move each conversation forwards.

I didn't want a full blown task manager (I pay for Todoist which fits perfectly), but I did want to track the state of each conversation in Claude from both the web app and the mobile. The result is a two fold solution, first there is a system prompt telling Claude to end each respond with either a 🔴, along with the next action required from me, or a ✅ which tells me the conversation is resolved. The second part of the solution is a Chrome extension which then automatically updates the title of any conversation with the red dot or green check mark, so I can tell at a glance which chats need work and which are done.

I do have a couple more features planned such as supporting other LLMs and a possible snooze feature. But for now it's a small working project that keeps my chats organised. It's available at bliptracker.xyz.

One final point on this project, I hope that eventually it gets replace by Anthropic building a better native product for tracking the status of chats, it's very limited right now. More widely this highlights that while new models are powerful and can do more, it still requires us as engineers to build products that solve actual problems in novel, tasteful and well designed solutions. That is what we pay for when buy a tool and what our users expect from us and something that no model as far as I can see will ever replace.

22 Jul 2026 5:00am GMT

Django: introducing django-crawl

I recently migrated one of my client projects from the legacy django-csp package to Django 6.0's built-in Content Security Policy (CSP) support (release note). This security header is a powerful tool for preventing unwanted content from being loaded on your site, so configuration correctness is paramount. The migration was fairly straightforward, but a few pages had complicated overrides, so I wanted to be sure that no CSP headers had been changed by my swapping of CSP implementations.

I had the idea to verify no page had changed its content-security-policy header by crawling the site with Django's test client, outputting URL and header contents during the process. By diffing the output from crawls before and after the migration, I could check for changes and track down which pages had been affected.

The core loop of that script looked something like this:

from collections import deque
from django.test import Client


client = Client()
client.force_login(superuser)

queue: deque[str] = deque(["/", "/admin/"])
...

while queue:
    url = queue.popleft()
    ...
    response = client.get(url, follow=False)
    ...
    print(f"{url}\t{response.headers.get('content-security-policy')}")
    ...
    for anchor in BeautifulSoup(response.content, "html.parser").find_all(
        "a", href=True
    ):
        # Enqueue these found links
        ...

This simple crawl of the site ended up flushing out seven non-CSP bugs, despite the project having 100% test coverage and a full suite of integration tests. Those bugs were due to incorrect link generation, admin features not being disabled, and regular old broken code.

I was pretty impressed with the power of this technique for finding broken stuff! Given this experience, I wanted to expand the script into a reusable tool, which I have now done with django-crawl.

To use django-crawl, install it, add it to INSTALLED_APPS, and you can run the crawl management command:

$ ./manage.py crawl -v 2
🐛 Crawling up to 1000 URLs, logged in as Ad Min
/
/about/
/blog/
/contact/
/dev/
/blog/2026/
/blog/2025/
/blog/2026/07/22/introducing-django-crawl/
...
🦋 Crawled 1000 URLs, encountered 0 errors, stopped due to reaching max URL limit of 1000.

The command reports any errors it encounters, from broken links to exceptions. The output uses Rich for pretty formatting and a live spinner while it runs. Adding -v 2 prints the URLs as they are crawled.

The crawler discovers links in various forms in HTML responses (<a href>, <link href>, <script src>, <img src>, etc.), sitemaps, and feeds. If you have a sitemap, you can start your crawl with a simple:

$ ./manage.py crawl /sitemap.xml

The HTML parsing is done with a custom Rust extension built with html5ever, the HTML parser from the Servo project, so it's very fast. And with no overhead from real HTTP requests or inter-process communication, the crawl is limited only by how fast your application code can run.

django-crawl also provides a Python API that you can use to make a mega-test that crawls your whole site with example data, raising an ExceptionGroup if any errors are encountered:

from django.contrib.auth.models import User
from django.test import TestCase

import django_crawl


class CrawlTests(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.admin = User.objects.create_superuser(username="admin")

    def test_crawl(self):
        client = django_crawl.CrawlClient()
        client.force_login(self.admin)
        django_crawl.crawl("/", "/admin/", client=client)

I am not sure if this is a good fit for most projects, since it will leave you with one long test that exercises many views. But it might be good for building a "safety net" on untested projects, something I know Jeff Triplett likes to do (ref Django Chat #24).

Fin

Please try out django-crawl today and let me know how it goes.

May your site not slow to a crawl,

-Adam

22 Jul 2026 4:00am GMT

21 Jul 2026

feedDjango community aggregator: Community blog posts

EuroPython 2026 Recap

Seven days of sponsor booth, talks, sprints, and hallway chats.

21 Jul 2026 11:56am GMT

20 Jul 2026

feedDjango community aggregator: Community blog posts

Deploying Web Apps in 2026: My EuroPython 2026 Conference Talk

A written guide to my recent EuroPython talk on modern Python web deployments.

20 Jul 2026 6:56am GMT

Best Django Redis configuration for speed and size

`lzma` compresses the most and `zlib` is about as fast as `zstd` in `django_redis` as compressor.

20 Jul 2026 1:01am GMT

19 Jul 2026

feedDjango community aggregator: Community blog posts

How I got Claude certified (and how you can too)

I'm Claude Certified Architect - Foundations now. Look at me.

A friend from work, Daniel, pinged me right after he started studying because he was confused and a little frustrated. He'd gone through the official docs, done a couple of practice exams, and felt like there was no connection between what he was studying and what the exam was actually testing. Fair. I felt the same way when I started. So we hopped on a call, I dumped everything I knew, and this post is basically that call cleaned up so more people can use it.

Fair warning up front: this is part study guide, part honest review. I'll tell you how to pass, but I'm also going to be honest about the parts that felt like studying for the exam rather than becoming a better engineer. Both things are true at once.

What I studied with

The exam I took is the Claude Certified Architect - Foundations. The single most useful resource for me was the Claude Certification Guide. The lessons are very good, and everything that showed up on my exam was covered by the syllabus there. I took notes like a maniac: more than half of a physical notebook, front and back, is just Claude notes from that site. I still recommend it without hesitation, because I genuinely learned a lot from it, not just enough to pass.

My notebook. Yikes.

The thing I liked most about it is that it teaches you to recognize the pitfalls the exam throws at you, without spoon-feeding you exactly what they are. So instead of memorizing "the answer is X," you build the instinct to spot what's going on. I prefer that. It stuck better.

One warning: don't over-index on practice exams. I did five or ten before the real thing, and the free mock exams floating around out there are way too basic compared to what you'll actually face. The guide's questions are the closest I found, and even those I wouldn't call identical to the real exam. Daniel was studying with a different mock exam site and the questions were so convoluted and samey that he said he fell asleep halfway through. So calibrate your expectations: use the mocks to get familiar with the format, not to predict the exact questions.

Study Claude CLI. Seriously. Study it.

This was the hardest part of the exam by far, and the part I was least prepared for.

I genuinely did not think they were going to ask about specific flags. The Claude CLI has something like a thousand of them, and my attitude going in was "I'm not learning all of this, if I need a flag I'll just run claude --help." In the real world, that's exactly what you do. Why would you memorize flags you can look up in two seconds? Daniel made this same point on our call, and honestly I agree with him.

But the exam doesn't care about that argument. They started asking about specific flags and what they do, and I sat there thinking I messed up.

So here's my advice: study the flags. You don't need to memorize all thousand of them, but go through the ones on the certification course and at least read each one and understand what it means. Not just claude -p. All of them. If you do one thing differently from how I studied, make it this.

Read the questions. Then read them again.

The exam is 60 questions, and you get 2 and a half hours. That's more than enough time. I finished the whole thing in about an hour and a half, went back through everything, and still submitted with time to spare. So don't rush.

But do read carefully, because the questions are convoluted. Sometimes it feels like they're testing whether you can read a wall of text, parse it, and pick the best answer, more than whether you know the material. English isn't my first language, and after about 45 minutes of dense, twisty questions I was toast. Budget your brain, not just your time.

A few tactics that worked for me:

The "pick the most correct answer" trap

This is the thing that trips everyone up, so it gets its own section.

A lot of questions have two answers that both technically work. The exam wants you to pick the one that's most correct, and "most correct" almost always means "the most Claude-native way of doing it."

Concrete example from the kind of question you'll see: you've got a process that runs sequentially and takes too long, and you need to cut the latency. One option is to implement a message queue to parallelize the slow tasks. Another is to spawn additional agents so the work gets split up. Both reduce latency. Both are reasonable. But Claude doesn't have a message queue, and the exam heavily favors two ideas: use Claude for everything, and let the agent take control. The parallel-agents answer wins because Claude decides how many agents to spawn, and if one fails it can respawn it. The queue answer works in real life, but it's not the answer the exam is looking for.

So when two answers both work, ask yourself: which one leans hardest into letting Claude do the thing? That's usually the "most correct" one.

The exam-day logistics nobody warns you about

The exam costs 125 USD, it's fully proctored, and the proctoring is strict. Here's what actually happens so you're not caught off guard:

None of this is hard, it's just a lot of process, and it's easier when you know it's coming.

So… is it actually worth it?

Here's the honest part, because Daniel asked me this directly and I don't want to pretend.

Did I learn to take an exam, or did I learn something real? My honest answer is about 50/50. A chunk of the studying was pure exam-prep: memorizing flags I'd normally just look up, learning to spot which answer the test wants. That part I won't oversell.

But the other half genuinely changed how I work. I picked up new things while studying and actually changed parts of my workflow afterward. So it's not just a piece of paper. There's real signal in there if you go in wanting to learn and not just wanting to pass.

Would I tell you to get certified? If your company is paying, or you've got the time and 125 bucks to spare, yeah, go for it. You'll come out a bit sharper and you get a shiny badge for LinkedIn. Just go in with clear eyes about which parts are learning and which parts are hoop-jumping.

Good luck. If you're studying for this and you get stuck, my inbox is open.

See you in the next one!

19 Jul 2026 5:00am GMT

18 Jul 2026

feedDjango community aggregator: Community blog posts

Migrating from FeinCMS to feincms3

Migrating from FeinCMS to feincms3

FeinCMS is still actively maintained, but development, bugfixes and new features mostly land on feincms3 and django-content-editor these days, not on FeinCMS itself. That's reason enough to eventually move a project over.

Someone asked on the feincms3 issue tracker whether there's a guide for making that move. There isn't one yet, so I thought I'd expand on my comment in the issue tracker and post it here too in the hope that it's useful to others. The post is based on a gradual migration we did in a large, long-lived Django project - a textbook publishing platform with years of content. Unfortunately I can't show more details since it's a commercial, closed source project. During the migration, the platform stayed in production the whole time, aside from the inevitable bug here and there.

The most important insight is that FeinCMS 1 content types and feincms3 plugins are close enough that we could keep using the same underlying database tables. An export/import step isn't required at all.

The overall shape of the migration

The examples below use Chapter and ChapterPlugin because that's the hierarchy in this particular project, one tree per book series rather than one global page tree. Most feincms3 projects center on a single Page model instead, so read Page wherever you see Chapter; the rest still applies.

Getting the migration state right

Here's a concrete proxy model from that migration, simplified. RichTextContent is our own abstract mixin, holding nothing but the actual text field, shared between the FeinCMS and feincms3 sides of the code base. The same role is played by feincms3.plugins.richtext.RichText if you use feincms3's bundled plugin instead of your own. ChapterPlugin in turn only wires up the boilerplate that's specific to being a plugin content type of our Chapter model:

class RichTextContent(models.Model):
    text = RichTextField()

    class Meta:
        abstract = True

class RichText(ChapterPlugin, RichTextContent):
    class Meta:
        db_table = "textbooks_chapter_richtextcontent"
        managed = False  # Proxy for the real model still owned by FeinCMS

The exact table name depends on how FeinCMS auto-generated it for your project (a mix of the app label, the base model and the content type name), so look it up rather than guessing. ./manage.py sqlmigrate or just inspecting the database will tell you.

For the very last step, once a plugin has been converted and managed = False can go away, use Django's migrations.SeparateDatabaseAndState. It lets you change the migration state without touching the database at all. That's exactly what you need here since the table already exists and already has the right shape; only Django's idea of what the schema is needs to catch up.

You don't even have to write these migrations by hand. Remove managed = False, run ./manage.py makemigrations as usual, and Django writes out the normal operations it would generate for any new model. The only manual step is moving that generated list of operations into the state_operations argument of a single SeparateDatabaseAndState operation, redacted and shortened here:

class Migration(migrations.Migration):
    dependencies = [
        ("textbooks", "0096_remove_richtextcontent_managed"),
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            state_operations=[
                migrations.CreateModel(
                    name="RichText",
                    fields=[
                        ("id", models.AutoField(primary_key=True, serialize=False)),
                        ("text", models.TextField()),
                        ("chapter", models.ForeignKey(to="textbooks.Chapter", ...)),
                    ],
                    options={"db_table": "textbooks_chapter_richtextcontent"},
                ),
            ],
            # No database_operations -- the table is already exactly like this.
        ),
    ]

As always, test this on a copy of the database first and make sure you have backups. Hand-editing migrations isn't generally recommended, but it's safe if you know exactly what you're doing. Treat it with the same care as any other schema change.

The page tree: mptt vs. tree-queries

FeinCMS 1's bundled Page model uses django-mptt for the page hierarchy, while feincms3's page comes with django-tree-queries instead. If you're using FeinCMS's own Page model and migrating to feincms3's, this can be a little bit painful since the database schema is different. There's a dedicated guide for migrating from django-mptt in the django-tree-queries documentation.

Once the last plugin has switched over, FeinCMS can be dropped from the project entirely, including from the requirements. The models end up exactly where they would have been if you'd started the project with feincms3 in the first place - and you never had to export or import a single row to get there.

18 Jul 2026 5:00pm GMT

17 Jul 2026

feedDjango community aggregator: Community blog posts

Issue 346: Supporting the Triptych Project

17 Jul 2026 3:00pm GMT

15 Jul 2026

feedDjango community aggregator: Community blog posts

Django: introducing django-orjson

Just as cars painted red are known to be faster, libraries implemented in Rust are also known to be faster. Today's example is orjson, a Rusty replacement for Python's built-in json module, boasting 10x faster serialization and 2x faster deserialization.

Such a library is great, but adopting it isn't easy, especially when your framework uses json in many different parts. To help Django developers adopt orjson, I have created django-orjson, which provides a whole bunch of drop-in replacements for Django and Django REST Framework (DRF) components backed by orjson.

For example, there's a version of JsonResponse:

from django_orjson.http import JsonResponse


def index(request):
    return JsonResponse({"title": "Hello, world!"})

…a test client with matching test case classes:

from django_orjson.test import SimpleTestCase


class IndexTests(SimpleTestCase):
    def test_index(self):
        response = self.client.get("/", headers={"accept": "application/json"})
        assert response.status_code == 200
        # response.json() uses orjson to parse the response body
        assert response.json() == {"title": "Hello, world!"}

…a version of Django's json_script template tag:

{% load django_orjson %}
{{ chart_data|json_script:"chart-data" }}

…and plenty more! All tested against the currently supported versions of Python and Django with 100% branch coverage.

While database queries tend to dominate the typical Django application's runtime, the time spent in serialization and deserialization can still be significant. That can make adopting orjson a nearly free performance win, which I hope django-orjson makes almost trivial for you.

Django proposal

After seeing the initial version of django-orjson, Paolo Melchiorre decided to push for adding orjson support to Django itself, in the new feature proposal Pluggable JSON serialization/deserialization backend. He made a thorough list of all the places in Django that could use orjson, and the proposal has gathered 14 thumbs-ups at the time of writing.

If you're interested in the topic of speeding up Django's JSON handling, check out the proposal and add your thoughts to the discussion.

Fin

Please try out django-orjson today and send me feedback.

YAML, TOML, or JSON?

-Adam

15 Jul 2026 4:00am GMT

14 Jul 2026

feedDjango community aggregator: Community blog posts

How to use a list/tuple/array in Django with a raw SQL cursor

This does not work:


from django.db import connection

list_of_values = [1, 2, 3]
with connection.cursor() as cursor:
    cursor.execute("""
        SELECT *
        FROM my_model_table
        WHERE some_value IN %s
    """, [
        tuple(list_of_values),
    ])
    results = cursor.fetchall()

It will give you:

django.db.utils.ProgrammingError: syntax error at or near "'(1,2,3)'"
LINE 4:         WHERE id IN '(1,2,3)'

It used to work with psycopg v2. Now, in psycopg v3, you have to use the ANY operator. See "You cannot use IN %s with a tuple"

This will work:


from django.db import connection

list_of_values = [1, 2, 3]
with connection.cursor() as cursor:
    cursor.execute(
        """
        SELECT *
        FROM my_model_table
        WHERE some_value = ANY(%s)
    """,
        [
            list_of_values,
        ],
    )
    results = cursor.fetchall()

Note the ANY(%s), and instead of a list that has a tuple, it's a list that has a list.

What About a List of Strings

Consider...


from django.db import connection

-list_of_values = [1, 2, 3]
+list_of_values = ['foo', 'bar', 'fiz']
with connection.cursor() as cursor:
    cursor.execute(
        """
        SELECT *
        FROM my_model_table
        WHERE some_value = ANY(%s)
    """,
        [
            list_of_values,
        ],
    )
    results = cursor.fetchall()

That will result in:

django.db.utils.DataError: invalid input syntax for type integer: "foo"
LINE 4:         WHERE some_value = ANY('{foo,bar,fiz}')

My solution was to rewrite the SQL string itself and treat each value as a parameter each. In other words, the SQL string, before being sent to cursor.execute(...) will contain something like this:


AND (
  some_value = % OR
  some_value = % OR
  some_value = % OR
  some_value = % OR
  -- ...etc...
  some_value = %
)

This will work and is safe:


from django.db import connection

list_of_values = ["foo", "bar", "fiz"]
with connection.cursor() as cursor:
    cursor.execute(
        f"""
        SELECT *
        FROM my_model_table
        WHERE ({" OR ".join(["some_value = %s" for _ in list_of_values])})
    """,
        list_of_values,
    )
    results = cursor.fetchall()

14 Jul 2026 6:14pm GMT

10 Jul 2026

feedDjango community aggregator: Community blog posts

Issue 345: Django security releases issued: 6.0.7 and 5.2.16

News

Django security releases issued: 6.0.7 and 5.2.16

Three new CEVs have been addressed in the latest security releases. We encourage all users of Django to upgrade as soon as possible.

Django on the Med: Venue and Hotel Details for Edition 2!

A few more confirmed details for Django on the Med 🏖️ 2026, which will take place from September 23 to 25, 2026 in Pescara, Italy 🇮🇹.

Thank you Lacey - Django Commons

Django Commons credits Lacey Henschel for helping shape the admin team from day one, including onboarding Django REST Framework, building the recruitment pipeline, and creating project check-ins that prevent stagnation. Her decision to step down is framed as proof that sustainability includes taking breaks without guilt, with hard judgment calls rooted in respecting maintainers and community trust.


Django Software Foundation

Last Call 2026 Django Developer Survey

The 2026 survey is ending next week on July 13th. Thank you to everyone who already filled it out. Please encourage all your friends and colleagues to do the same. This is the single most important tool for collecting data from the Django community and directly influences the work of Fellows and new features.


Updates to Django

Today, "Updates to Django" is presented by Raffaella from Djangonaut Space! 🚀

Last week we had 6 pull requests merged into Django by 5 different contributors

Some interesting post from the Django Forum:


Sponsored Link

Level up with mentorship

You can have a great manager and still want an outside perspective. I explain why in my FAQ.


Articles

The Missing Link: Thinking in Use Cases with Django Query Selectors

Where your queries should live - and how selectors keep your business logic lean and readable.

The Missing Link: Thinking in Use Cases with Django Query Selectors

Atomic, chainable queryset methods answer how you fetch; selectors answer what you are fetching for. Move each read use case into a named, testable function that composes CQS methods, so views and services stay thin and business logic stops spreading across views and forms.

Nifty Django Feature: resolve function

Django's resolve() turns a request path into a ResolverMatch, giving you the target view function, extracted kwargs like pet_id, and the URL name. The same mechanism can be applied to your web server logs to reconstruct which views users hit over time, as long as you track URL changes between deployments.

How to Read Postgres EXPLAIN: A Guide to Scan Types

Scan type in a Postgres EXPLAIN plan tells you whether the database reads the whole table, walks an index, builds a bitmap, or even satisfies the query entirely from an index (index-only scan). This guide walks through sequential, index, bitmap heap, parallel variants, and index-only scans so you can spot why a query is slow and what the planner is optimizing for.

Why we built yet another Postgres connection pooler

Connection poolers often break session state, forcing apps to stop relying on SET and sidelining LISTEN/NOTIFY semantics. PgDog adds a SQL-aware layer that tracks SET variables per client and proxies LISTEN/NOTIFY across processes while preserving transactional behavior, so scaling doesn't mean rewriting core Postgres usage.

A small proposal to form rendering in Django

A code example around this new feature idea, which is an extension to Django's form rendering capabilities to include widgets templates inside a form renderer.

Fixing the dictionary with Python 3.14

A Hugo van Kemenade look at "And now for something completely different" in the Python 3.14 cycle starts with the π symbol and an Oxford English Dictionary markup mistake. The reported rendering bug was fixed within about a year, highlighting how even reference sites can need careful dictionary-grade scrutiny.

How to publish to PyPI using GitHub Actions securely

GitHub Actions incidents have pushed many teams to tighten publishing workflows, and this guide lays out three practical steps for PyPI publishing: run zizmor, remove overly broad GITHUB_TOKEN permissions and persisted checkout credentials, and pin actions to commit SHAs. It also recommends using PyPI Trusted Publishing with a GitHub environment that requires an approval gate before releases.


Videos

Updates on Django's Async Story - Talk Python Live Stream

Carlton Gibson joined host Michael Kennedy to provide an in-depth look at Django's ongoing async story, where it stands now, and what to expect in future releases.


Django Fellow Reports

Jacob Walls

Jacob is on vacation this week.

Natalia Bidart

Intense week! ✨ I was mostly covering solo this week ⛑️, so it was a mix of keeping everything moving and diving deep where needed. A big chunk of time went into tracking down and fixing a docs build regression for the website (thanks Carlton for spotting it and Tobias for the help debugging), which uncovered a subtle mismatch between how Django (core) builds docs and how the website consumes them. Alongside that, I spent time on a few deeper investigations that had been lingering (snoozed over and over in my inbox ⏰), finally unblocking design questions and follow-ups that needed proper attention. On the security side 🔐, I handled prenotifications and a wave of incoming reports, closing out a number of invalid ones and keeping things tidy.

Overall, a very hands-on week 🧰 balancing throughput with some worthwhile deep dives that should pay off going forward ⚖️.


Projects

otto-torino/django-baton

A cool, modern and responsive django admin application based on bootstrap 5 that brings AI to the Django admin.

unfoldadmin/django-unfold

A modern Django Admin approach.

10 Jul 2026 3:00pm GMT

09 Jul 2026

feedDjango community aggregator: Community blog posts

Foss4g NL: early afternoon sessions

(One of my summaries of the 2026 one-day Foss4g open source geo conference in Groningen, NL).

Accessibility: geoinformation for everybody - Liliana Santoso-Avis & Jedidja van der Sluis - Stoutjesdijk

WCAG (Web Content Accessibility Guidelines) deals with accessibility (a11y). (I personally try to take accessibility a bit into account, proper headings and reasonably contrast-rich colors on my website, for instance. I've made other summaries of "a11y" talks, for instance this one about accessible documentation, held at the 2025 pycon.de.

It is not just accessibility, but really about the quality of the information as a whole. Thinking about the accessibility guidelines (listed below) helps you create better information projects.

  • Perceivable
  • Operable, for instance navigating a website with keyboard instead of mouse.
  • Understandable
  • Robust

When making a map viewer, we often claim "we're an exception", but that's not fully the case. Your map component should not be a "keyboard trap", for instance. And the contrast of your map should be right. And if the map is essential for navigating through the rest of the site, you also can't claim an exception.

You need a mindset shift. From "bah, extra work" to "hurray, better work".

They started with an inventory, for instance of the applicable laws. Then getting the roles/responsibilities right. Then lots of experience sharing. Now they want to get certification for the work they did. And they want to do outreach. And they now try to cooperate with partners (like other provinces and government agencies), software companies and other organisations.

In tourist areas, you sometimes have tactile maps. You can also do that in Qgis! You can print those maps. https://touch-mapper.org/en/

Colors: don't use only colors to indicate differences. Also differ the shapes of points, for instance. As a test, try to sort M&Ms while wearing colored glasses...

Some browser tools: taba11y to show the tab order of your site. Color contrast checker, heading map, leat's get color blind, link checker, WCAG color contrast checker.

GeoNode: digital sovereignty in practice - Finn Peranovich & Guido Schaepman

Two Dutch water boards, Rijnland and Schieland en de Krimpenerwaard, cooperated in a project to move to open source with GeoNode.

They did an inventory in 2024 whether open source was an option. They looked at the current usage and identified possible open source alternatives. Open source promised more autonomy (no ESRI lock-in, geopolitical, etc.), lower costs (the costs of switching would be paid back within three years), more innovation and better compliance (both NL and EU laws).

The first test was with public-facing data that previously was served with ArcGIS server.

Geonode is a management layer on top of geoserver. It uses open source tools like Django, Mapstore, Postgresql, RabbitMQ. They run Geoserver and GeoNode inside a kubernetes cluster. Conversion from ArcGIS server was done with several homemade scripts.

Tip: Qgis has a handy Geonode plugin for browsing everything in your Geonode.

They were surprised by the quality of GeoNode: everything they needed from ArcGIS server is also available in GeoNode. They're currently in the test phase, they'll soon go to production. They really want to make other water boards enthusiastic about open source, too, hopefully leading to cost sharing.

https://reinout.vanrees.org/images/2026/straalzender2.jpeg

Unrelated photo: we have two offices in the center of Utrecht. As a handy connection, we're using a radio link ("straalverbinding") between the two. We have line of sight, as you can see in this photo. The dark gray wall to the right of the far radio link doesn't look like much, but it is part of our office and part of one of the oldest buildings (around 1200!) in Utrecht. (See wikipedia).

09 Jul 2026 4:00am GMT

08 Jul 2026

feedDjango community aggregator: Community blog posts

A small proposal to form rendering in Django

It's been a while since my last post, mainly because June saw me start a new client, GSOC really taking off and we have our first real customers in Hamilton Rock with money being deposited and some money being spent, not without its teething issues! Also with a fair amount of social engagements as well!

But anyway, on to today's post. During June I proposed a new feature idea which is an extension to Django's form rendering capabilities to include widgets templates inside a form renderer. Currently, it's only possible to Override widgets at a project level by specifying the template name, or you have to overwrite the widget and then specify your own custom template name and then use that custom widget. It's not possible to customize widgets at the form renderer level.

My idea is to extend the form renderer API. Well actually extends the budget rendering API to check the specified form renderer. It should only be an extension to a private method inside the widget API. Below is the relevant code that I actually got Claude to spit out inside Hamilton Rock today. This is a first iteration which very likely needs some improvement, but it does work!

_CAMEL_BOUNDARY = re.compile(r"(?<!^)(?=[A-Z])")

class Widget(metaclass=MediaDefiningClass):
    ...
    
    def _render(self, template_name, context, renderer=None):
        if renderer is None:
            renderer = get_default_renderer()
        # Walk the widget MRO for a ``<widget>_template_name`` on the renderer.
        # A class that defines its own ``template_name`` short-circuits (attribute
        # shadowing): a custom widget keeps its template over a base override,
        # while an unstyled subclass resolves up to a styled base.
        for klass in type(self).__mro__:
            slug = _CAMEL_BOUNDARY.sub("_", klass.__name__).lower()
            override = getattr(renderer, f"{slug}_template_name", None)
            if override is not None:
                template_name = override
                break
            if "template_name" in klass.__dict__:
                break
        # Same trust posture as Django's own Widget._render.
        return mark_safe(renderer.render(template_name, context))  # noqa: S308

and here is the current method from the source

    def _render(self, template_name, context, renderer=None):
        if renderer is None:
            renderer = get_default_renderer()
        return mark_safe(renderer.render(template_name, context))

There is also some code to allow admin classes to specify a renderer so that your custom renderer doesn't overwrite admin form widgets. In the coming week or so, I will extract this code into a third-party package for others to use.

But what's the real win with this potential change? Honestly I see this unlocking simple packages which unlock custom and complete form rendering packages with Django. Most of these themes would be HTML, CSS & Javascript, with the only python being the declaration of the FormRenderer class like so (pulled from Hamilton Rock):

class DrawerFormRenderer(TemplatesSetting):
    form_template_name = "forms/drawer_form.html#form"
    field_template_name = "forms/drawer_form.html#field"

    text_input_template_name = "forms/drawer_form.html#text_input"
    email_input_template_name = "forms/drawer_form.html#text_input"
    password_input_template_name = "forms/drawer_form.html#text_input"
    date_input_template_name = "forms/drawer_form.html#text_input"
    number_input_template_name = "forms/drawer_form.html#number_input"
    select_template_name = "forms/drawer_form.html#select"
    textarea_template_name = "forms/drawer_form.html#textarea"
    checkbox_input_template_name = "forms/drawer_form.html#checkbox"
    radio_select_template_name = "forms/drawer_form.html#radio"

If you like the look of this, give the feature a thumbs up on the issue and we can hopefully get it progressed. Also do let me know what glaring holes that I have missed in this idea.

08 Jul 2026 5:00am GMT

03 Jul 2026

feedDjango community aggregator: Community blog posts

Issue 344: Happy Birthday Djangonaut Space!

03 Jul 2026 3:00pm GMT