01 Dec 2025

feedDjango community aggregator: Community blog posts

Safe Django database migrations on Coolify

Deploying Django on Coolify has been fantastic so far: automatic builds, atomic releases, ephemeral containers, and simple scaling. In a previous article I explained how I set up my Django projects in Coolify, including the fact that migrations run as part of the build step. This works great for most migrations: failures abort the build, no partial deploys, no surprises.

But it breaks down for one specific class of migrations: schema-destructive migrations, i.e. migrations that remove fields, drop tables, rename columns, or otherwise make the existing running code incompatible with the current database schema.

Coolify builds your new container, applies the migrations, and only afterwards starts replacing the running container with the new one. During that in-between period (usually 1-2 minutes depending on your image size) your old Django container is still running code that expects the old schema. If a column has just been removed… boom: 500 errors for users until the new container becomes healthy and takes over.

Why you can't just move the migration step

Your first instinct might be to change when the migrations run. Let's look at some alternatives and why they don't solve the root problem.

Strategy A: the post-deploy hook

You could remove migrate from the Dockerfile and run it in a "Post-Deploy" hook (or as part of the container startup command). This means migrations run after the new container starts or just before the switch-over.

This fixes the "removing a field" problem, because the schema change happens after all old containers are gone. But it breaks the "adding a field" problem: if you add a new required column, the new code in the new container might start up and try to query that column before the migration finishes. Result: the new app crashes on startup, and the deployment fails.

Another issue: if migrations fail, your deployment still succeeds, leaving your app running with mismatched code and schema.

Verdict: worse than before.

Strategy B: separate migration job

You could create a second service in the same project that runs migrations as a one-shot job.

The problem is that you still have to choose: run it before the deploy, or after?

You've essentially re-implemented either Strategy A or the original "migrate during build" approach, just in a second container. The core compatibility problem remains.

Verdict: more complex and still unsafe.

Strategy C: blue/green databases

This is the most elaborate workaround: copy production to a new database, run migrations there, and then point the new code to the new DB.

This is incredibly complex to manage for data consistency, and it would be catastrophic for any e-commerce site:

10:00:00 - Start cloning production DB
10:00:30 - User places $500 order (written to old DB)
10:01:00 - Clone complete, run migrations on clone
10:01:30 - User registers account (written to old DB)
10:02:00 - Switch to new DB
10:02:01 - Previous order and user… GONE 💀

You're solving the wrong problem with a rocket launcher. This is enterprise-grade DevOps machinery for a basic schema compatibility issue.

Verdict: massive complexity, no real benefit.

The real solution: the two-phase deploy

The hard truth is that database migrations cannot be strictly zero-downtime if they break backward compatibility. The root problem is not when migrations run. The problem is that old and new code are talking to the same database during the deploy, so the schema must be compatible with both.

The solution is not infrastructure; it's application patterns. The key idea: Decouple the code change from the schema change. This is known as the Two-Phase Deploy Pattern, also called expand-and-contract, non-breaking migrations, or safe migrations.

Example 1: removing a field safely

Let's say we want to remove the phone_number field from our User model. The simplest way is sadly the wrong way: delete the field from models.py, run makemigrations, and deploy. This causes the server errors described above.

Instead, split it into two deploys.

Phase 1: expand (make schema compatible with both versions)

We stop using the field in code, but we keep the column in the database and make sure it doesn't break either version.

First we make the field nullable so the new code can ignore it:

# models.py
class User(models.Model):
    ...
    # We want to delete this, but first we make it nullable
    phone_number = models.TextField(null=True, blank=True)

Then remove all references to user.phone_number in templates, views, and serializers. Now it's safe to create a migration and deploy this version.

Result:

Even if some old code hits that field for a moment, it still exists, so nothing crashes.

Phase 2: contract (remove old schema elements)

Now that the production code no longer uses phone_number, we can safely drop it. Delete the field from models.py:

# models.py
class User(models.Model):
    ...
    # phone_number is gone

Create a migration and deploy this version.

Result:

No server errors.

Example 2: renaming a field safely

Renaming a field is just "remove old field + add new field," so the same pattern applies.

Phase 1: add new field + dual-write + data migration

class User(models.Model):
    old_name = models.CharField(max_length=100)
    new_name = models.CharField(max_length=100, null=True)

    def save(self, *args, **kwargs):
        # Dual-write during transition
        if self.old_name and not self.new_name:
            self.new_name = self.old_name
        super().save(*args, **kwargs)

Update your app to use new_name everywhere, but keep writing both fields for now.

Then add a data migration to your migration file:

from django.db.models import F

def copy_old_to_new(apps, schema_editor):
    User = apps.get_model('accounts', 'User')
    User.objects.filter(new_name__isnull=True).update(new_name=F('old_name'))

class Migration(migrations.Migration):
    operations = [
        migrations.AddField(...),
        migrations.RunPython(copy_old_to_new, migrations.RunPython.noop),
    ]

After deploying this version and letting it run for a while, all users should now have new_name populated, and dual-writes have ensured the values stayed in sync.

Phase 2: remove old field

Now remove old_name and the dual-write logic:

class User(models.Model):
    new_name = models.CharField(max_length=100)

Generate the migration, deploy, and you're done.

Summary

Running migrations during your Coolify build is good practice - it catches failures early and keeps your deploys atomic. But schema-destructive migrations will always conflict with rolling updates if they break compatibility between old code and the new schema.

Instead of bending Coolify into a complicated orchestration engine, embrace the proven approach: deploy schema changes in two phases, keeping them backwards-compatible.

You should use this pattern for all kinds of destructive changes:

It's simple, safe, predictable, and works with every hosting platform, including Coolify.

01 Dec 2025 6:14pm GMT

28 Nov 2025

feedDjango community aggregator: Community blog posts

Django News - Sales and AI in the Real World - Nov 28th 2025

News

Python Black Friday & Cyber Monday sales (2025)

More Black Friday and Cyber Monday deals for Python and Django developers!

LearnDjango has 50% off courses too!

treyhunner.com

Django Software Foundation

DSF member of the month - Akio Ogasahara

Akio Ogasahara, DSF member of the month, contributes extensive Japanese documentation translation, advocates Django admin for operations and highlights Django security alongside AI assisted development.

djangoproject.com

Python Software Foundation

PyPI and Shai-Hulud: Staying Secure Amid Emerging Threats

PyPI warns developers about the Shai-Hulud npm supply chain campaign, revoking exposed tokens and recommending trusted publishers, CI workflow audits, and token rotation.

pypi.org

Wagtail CMS News

Wagtail 7.2.1

Wagtail shipped several fixes that improve userbar previews, document and image handling, search stability, and reference index performance, along with a small search test cleanup.

github.com

Sponsored Link 1

Sleep tight with HackSoft and our Django services!

While you recharge, we keep your software running smoothly - secure, stable, and ready for tomorrow. We are HackSoft - your Django development partner, beyond code. Learn more!

hacksoft.io

Articles

Django: implement HTTP bearer authentication

Shows how to implement simple single token HTTP Bearer authentication in Django views with secure compare, unit tests, and a reusable decorator.

adamj.eu

Building a Translations Dashboard In Wagtail

Built a custom Wagtail dashboard using wagtail localize to list original pages, show per locale translation percentages, and add filters and page explorer links.

lincolnloop.com

Open source funding in 2025

Buttondown updates its open source funding and developer stack, continuing significant support for Django and Python while simplifying tooling and supply chain.

buttondown.com

Upgrading Postgres Major, and Django model with Logical Replication.

Use Postgres logical replication to migrate from v13 to v16 with the new Django schema already applied and temporary columns to enable minimal downtime switchover.

tr3s.ma

We should all be using dependency cooldowns

Use dependency cooldowns (for example Dependabot or Renovate) to block most open source supply chain attacks by delaying new releases several days.

yossarian.net

Django and Password Manager SDKs

A look at how Django could integrate with modern password-manager SDKs-like Bitwarden and 1Password-to securely store dynamic API credentials using pluggable secret backends instead of plain database fields.

softwarecrafts.co.uk

Setting secrets in env vars

Use 1Password CLI with direnv on macOS to load secrets into ephemeral environment variables and avoid long lived tokens, prefer PyPI Trusted Publishing.

hugovk.dev

The varying strictness of TypedDict

Python 3.15 TypedDict introduces closed and extra_items to forbid unknown keys or type them, resolving Mapping compatibility issues with strict type checkers.

snarky.ca

Why your mock breaks later

Patch dependencies where your code imports them rather than builtins to avoid global side effects that break tools like coverage.py and other tests.

nedbatchelder.com

Events

PyCascades 2026

PyCascades 2026 is March 21 & 22 in Vancouver, British Columbia.

pycascades.com

Podcasts

Django Chat #190: AI in the Real World - Marlene Mhangami & Tim Allen

Marlene and Tim both gave talks on AI at the recent DjangoCon US conference, but with very different angles. In this episode, we discuss the real-world strengths and weaknesses of AI, how it is impacting developers' daily workflows, and also examples of AI failures. Marlene is a Senior Developer Advocate at Microsoft and Tim is the Principal Engineer at Wharton Research Data Services.

djangochat.com

Projects

vintasoftware/django-ai-boost

A MCP server for Django applications, inspired by Laravel Boost.

github.com

adamghill/dj-waf

Add WAF rules to block known bots and malicious traffic for Django applications. Provides easy integration with popular WAF services like Cloudflare.

github.com


This RSS feed is published on https://django-news.com/. You can also subscribe via email.

28 Nov 2025 6:00pm GMT

Stop scrolling the admin apps

Below is a tiny javascript snippet to add to the end of the admin/base.html. This little snippet with ensure the current app in the left hand navigation is always at the top of the viewport when navigating between admin pages. Very handy when you have lots of apps and models!

<script>
  const current_app_nav = document.querySelector(".current-app");
  current_app_nav.scrollIntoView(true, {block: 'center', container: 'nearest', inline: 'nearest'});
  window.scrollBy(0, -100);
</script>

Enjoy!

28 Nov 2025 6:00am GMT

26 Nov 2025

feedDjango community aggregator: Community blog posts

AI in the Real World - Marlene Mhangami & Tim Allen

Sponsor

This episode was brought to you by HackSoft, your development partner beyond code. From custom software development to consulting, team augmentation, or opening an office in Bulgaria, they're ready to take your Django project to the next level!

26 Nov 2025 6:00pm GMT

Django and password manager SDKs

In my current project, I'm going to be storing a fair number of different API credentials, first those that we own and then plenty of OAuth credentials from our customers. Today I am pondering the first scenario and wondering what how I can store these securely and with the prinicple of least privilege.

Currently I'm using django-allauth's socialaccount models to store these details, it's a nice abstraction and I can add relationships from my models to the models allauth provides to dynamically select the appropriate credentials I need to access the relevant API. However the secrets are stored in plain CharFields and are accessible from the admin. That's fine for now, but soon that's not going to fly.

I could store these as environment variables, but this goes against the current dynamic design of holding configuration in the database, which allows me to switch API clients and tokens without a code deploy. Last night I was listening to a 1password advert about their SDK which goes beyond a CLI interface allowing developers to interact with their platform. Bitwarden (my password manager of choice) also has this capability and this got me wondering, what would Django integration to these providers look like?

Off the top of my head there are a few possible integration points. First is via settings where we could dynamically allow Django access to a secret or set of secrets and then we only have to store a single access point outside of the manager; This is useful, not aligned to the design above. The other two integration points would be having either a SecretManager Model or SecretField. The model would provide a local proxy to interact with secrets (eg store extra metadata or related to from other models), but a certain fields (SecretField etc) would call out to the SDK to retrieve secrets, usernames or other details stored in the secure vault. The SecretField implementation is a smaller implementation that could be added to other normal models, where the local database stores the reference to the secret and then provides access to the secret via the SDK.

The interesting design here would be providing a python API that would allow a developer to choose a secrets backend for this model or field. I have listed 2 above, but I know the larger cloud providers have services like this, Hashicorp has Vault, Kubernetes likely has something as well, and there should probably be an option to fall back to a file or environment variables.

I would be interested to hear of similar work or packages if they exist! (A quick search on django packages reveals at least one package)

26 Nov 2025 6:00am GMT

25 Nov 2025

feedDjango community aggregator: Community blog posts

Django: implement HTTP bearer authentication

HTTP has a general authentication framework that defines a pattern into which various authentication schemes can fit. Clients may provide an authorization request header that contains a credential. If authorization is missing or invalid, the server may respond with a 401 (Unauthorized) status code, including a www-authenticate header advertising what authentication schemes are supported. Otherwise, the server can respond with the authenticated resource.

The simplest authentication scheme in this framework is called Bearer, where the client needs to provide a valid token (typically a randomly generated string) in authorization. Bearer authentication is commonly used in APIs, where it's convenient to provide a single token rather than a username and password.

Django-based API frameworks provide built-in support for Bearer authentication, such as Django REST Framework's TokenAuthentication or django-ninja's authentication layer. But for simple cases, such frameworks can be a bit heavyweight, and you might want to implement Bearer authentication yourself, which only takes a few lines of code.

Here's an example implementing single-token Bearer authentication for a Django view returning JSON data:

import os
import secrets
from http import HTTPStatus

from django.http import JsonResponse

SECRET_STUFF_TOKEN = os.environ.get("SECRET_STUFF_TOKEN", "")


def secret_stuff(request):
    authorization = request.headers.get("authorization", "")
    if not SECRET_STUFF_TOKEN or not secrets.compare_digest(
        f"Bearer {SECRET_STUFF_TOKEN}", authorization
    ):
        return JsonResponse(
            {"detail": "Unauthorized"},
            status=HTTPStatus.UNAUTHORIZED,
            headers={
                "www-authenticate": 'Bearer realm="Secret area!"',
            },
        )

    return JsonResponse({"answer": 42})

In this example, there's a single valid token, stored in the SECRET_STUFF_TOKEN environment variable. The view code checks if the request's authorization header matches the expected value, using secrets.compare_digest() to avoid timing attacks.

If the header is invalid, the view responds with an appropriate 401 Unauthorized response, including a www-authenticate header advertising the Bearer scheme. Otherwise, the token is assumed valid and the view returns the secret data (the answer is 42!).

We can test this view with some unit tests using Django's test client:

from unittest import mock

from django.test import SimpleTestCase

from example import views


class SecretStuffTests(SimpleTestCase):
    def test_unauthorized_no_header(self):
        response = self.client.get("/secret-stuff/")

        assert response.status_code == 401
        assert response.json() == {"detail": "Unauthorized"}
        assert "www-authenticate" in response.headers
        assert response.headers["www-authenticate"] == 'Bearer realm="Secret area!"'

    def test_unauthorized_invalid_token(self):
        response = self.client.get(
            "/secret-stuff/",
            headers={"authorization": "Bearer hunter1"},
        )

        assert response.status_code == 401
        assert response.json() == {"detail": "Unauthorized"}
        assert "www-authenticate" in response.headers
        assert response.headers["www-authenticate"] == 'Bearer realm="Secret area!"'

    def test_authorized(self):
        secret_token = "hunter2"
        with mock.patch.object(views, "SECRET_STUFF_TOKEN", secret_token):
            response = self.client.get(
                "/secret-stuff/",
                headers={"authorization": f"Bearer {secret_token}"},
            )

            assert response.status_code == 200
            assert response.json() == {"answer": 42}

These tests cover the three cases: no authorization header, an incorrect token, and the correct token respectively.

Make a decorator to reduce repetitive repetition

For authenticating multiple views, it's convenient to extract the authentication logic into a view decorator, like:

import functools
import os
import secrets
from http import HTTPStatus

from django.http import JsonResponse

SECRET_STUFF_TOKEN = os.environ.get("SECRET_STUFF_TOKEN", "")


def bearer_auth(view_func):
    @functools.wraps(view_func)
    def wrapper(request, *args, **kwargs):
        authorization = request.headers.get("authorization", "")
        if not SECRET_STUFF_TOKEN or not secrets.compare_digest(
            f"Bearer {SECRET_STUFF_TOKEN}", authorization
        ):
            return JsonResponse(
                {"detail": "Unauthorized"},
                status=HTTPStatus.UNAUTHORIZED,
                headers={
                    "www-authenticate": 'Bearer realm="Secret area!"',
                },
            )
        return view_func(request, *args, **kwargs)

    return wrapper


@bearer_auth
def secret_answer(request):
    return JsonResponse({"answer": 42})


@bearer_auth
def secret_tip(request):
    return JsonResponse({"tip": "The cake is a lie."})

Extensions

Having a single hardcoded token may be all you need, for example for an internal API that will only be accessed by a single trusted client. But in more complex scenarios, you may want to support multiple tokens, token revocation, token expiration, or scopes/permissions. In these cases, you might want to extend the above code to use tokens stored in a database model. And if you need a lot of features, it may be time to consider a framework like Django REST Framework or django-ninja.

Fin

May the bearer of this blog post implement authentication exceedingly successfully,

-Adam

25 Nov 2025 6:00am GMT

21 Nov 2025

feedDjango community aggregator: Community blog posts

Django News - Django 6.0 release candidate 1 released - Nov 21st 2025

News

Django 6.0 release candidate 1 released

Django 6.0 release candidate 1 is now available. It represents the final opportunity for you to try out a mosaic of modern tools and thoughtful design before Django 6.0 is released.

djangoproject.com

Python Insider: Python 3.15.0 alpha 2

This release, 3.15.0a2, is the second of seven planned alpha releases. Alpha releases are intended to make it easier to test the current state of new features and bug fixes and to test the release process.

blogspot.com

Django Software Foundation

Twenty years of Django releases

Since we're celebrating Django's 20th birthday this year, here are a few release-related numbers that represent Django's history:

djangoproject.com

Python Software Foundation

New Login Verification for TOTP-based Logins

PyPI has added email verification for TOTP-based logins

pypi.org

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 9 different contributors - including 2 first-time contributors! Congratulations to Hong Xu and Benedict Etzel for having their first commits merged into Django - welcome on board!

News in Django 6.1:

The admin site login view now redirects authenticated users to the next URL, if available, instead of always redirecting to the admin index page.

Inspectdb now introspects HStoreField when psycopg 3.2+ is installed and django.contrib.postgres is in INSTALLED_APPS.

Django Newsletter

Sponsored Link 1

LearnDjango.com Black Friday Sale - 50% Off

This is the only annual discount available for lifetime access to three books by Will Vincent: Django for Beginners, Django for APIs, and Django for Professionals.

learndjango.com

Articles

Django-related Deals for Black Friday 2025

Adam Johnson has posted his now annual listing of Django-related Black Friday deals with discounts on various books, packages, services, and more.

adamj.eu

Open source funding in 2025

Buttondown has long-maintained a page of open source usage and contributions. This update adds two new tools. It would be wonderful if all companies acted like this!

buttondown.com

How to use UUIDv7 in Python, Django and PostgreSQL

Learn how to use UUIDv7 today with stable releases of Python 3.14, Django 5.2 and PostgreSQL 18. A step by step guide showing how to generate UUIDv7 in Python, store them in Django models, use PostgreSQL native functions and build time ordered primary keys without writing SQL.

paulox.net

Planning My (Django) Retirement (Again)

Carlton Gibson reflects on his continued involvement with Django (in so many ways!) and also actual plans to step away a bit over the coming year.

noumenal.es

Beyond ruff: Boa Restrictor is the new Python linter on the block

How opinionated tooling will save your day - or night.

medium.com

Cross-Site Request Forgery

A very good description of this long-standing security risk in web development.

filippo.io

Going build-free with native JavaScript modules

Modern browsers support native JavaScript modules and CSS features, so Django projects can skip frontend build tools while using ManifestStaticFilesStorage for production.

djangoproject.com

How to display a JSON value in Django admin (when using MySQL)

Show how to extract and cast a JSON value in MySQL-backed Django models to annotate and sort datetime fields in the admin list view.

enriquesoria.com

Understanding the Different POST Content Types

Practical overview of POST content types with Django examples showing request parsing and validation for form, multipart, JSON, NDJSON, text, XML, and binary.

djangotricks.com

Django Fellow Report

Fellow Report - Natalia

Another week with a strong focus on security work. Most of the effort went into preparing and issuing the November security release, along with some follow-up permission and access reviews. CNA tasks and training also continued in the background.

djangoproject.com

Fellow Report - Jacob

This week we landed a migrations fix that prevents flaky CircularDependencyErrorswhen squashed replacements are in play. If you haven't tried squashing migrations in a while, check out main and give it another go!

We also fixed an unreleased regression in the urlize template filter-big thanks to Mehraz Hossain Rumman for testing the beta. (Are you the next tester to report a regression before 6.0 final?)

djangoproject.com

Forum

Pre-PEP: Rust for CPython - Core Development

A proposal to introduce the Rust programming language to CPython.

python.org

Django News Jobs

Job Application for Senior Application Security Engineer at Energy Solutions - USA

Senior Back-End Developer at Showcare

Django Newsletter

Django Forum

Add Plausible Tracking to DjangoProject.com?

An ongoing thread around adding anonymized tracking to the djangoproject.com website.

djangoproject.com

Projects

ambient-innovation/boa-restrictor

A Python and Django linting library.

github.com

pls-rs/pls

pls is a prettier and powerful ls(1) for the pros.

github.com

blighj/django-manifeststaticfiles-enhanced

Enhanced ManifestStaticFilesStorage for Django.

github.com


This RSS feed is published on https://django-news.com/. You can also subscribe via email.

21 Nov 2025 5:00pm GMT

20 Nov 2025

feedDjango community aggregator: Community blog posts

Django-related Deals for Black Friday 2025

Here are some Django-related deals for this year's Black Friday (28th November) and Cyber Monday (1st December), including my own.

I'll keep this post up to date with any new deals I learn about. If you are also a creator, email me with details of your offer and I'll add it here.

My books

My four books have a 50% discount, for both individual and team licenses, until the end of Cyber Monday (1st December), including Boost Your GitHub DX, which I released last week. This deal stacks with the bundle offers and purchasing power parity discount for those in lower-income countries.

Individual books:

Bundles:

Adam Johnson book sale 2025

Aidas Bendoraitis' paid packages

Aidas Bendoraitis of djangotricks.com has created three paid packages. Use the links below for a 20% discount, available until the end of the 1st December.

  • Django GDPR Cookie Consent - a customizable, self-hosted cookie consent screen. This package takes the pain out of setting up legally-mandated cookie banners and settings, without using an expensive or inflexible vendor.

    Buy it on Gumroad

  • Django Paddle Subscriptions - an integration with Paddle's billing API for subscriptions. This package allows you to collect SaaS payments internationally with a reliable payment processor.

    Buy it on Gumroad

  • Django Messaging - ready-to-use, real-time solution for Django that saves months of development. It offers private and group chats, embeddable widgets, flexible settings, a modern UI, and supports both WebSocket and polling.

    Buy it on Gumroad

Aidas Bendoraitis pacakages sale 2025

Appliku

Appliku is a deployment tool designed for Django. It can deploy your project to AWS, DigitalOcean, Hetzner, and other cloud servers.

They're offering 30% off all annual plans, for one year, until the 1st December. Use code BLACKFRIDAY2025 at checkout.

Buy on the Appliku site

Appliku sale 2025

Async Patterns in Django

This book is a tour through the advanced topic of asynchronous programming in Django. It covers the range of tools and protocols available for asynchronous behaviour in your web application. It's written by Paul Bailey, an experienced Principal Engineer.

Paul is offering ~50% off the book with the coupon link, discounting the book from $39.95 to $21. This is available until the 1st December.

Buy on Leanpub

Async Patterns in Django sale 2025

SaaS Pegasus

Cory Zue's SaaS Pegasus is a configurable Django project template with many preset niceties, including teams, Stripe subscriptions, a front end pipeline, and built-in AI tooling. It can massively accelerate setting up a SaaS in Django.

The "unlimited license" is discounted 50%, from $999 to $499.50. This deal is available from the 21st November until the 3rd December.

Buy it on saaspegasus.com

SaaS Pegasus sale 2025

Bonus: Django itself

Django is maintained by the Django Software Foundation (DSF), a non-profit organization that relies on donations to fund its work. So while it cannot run sales, supporting it is definitely a good deal!

If your organization relies on Django, please push to sign it up as a corporate sponsor. For $1,000 or more, you can get your logo featured on the Fundraising page, and you can feature a badge on your own site.

Otherwise, you can also donate as an individual on:

Your money will go towards:

  • Paying the Django Fellows, Natalia, Sarah, and Jacob, who merge respond to tickets, merge code, and make releases.
  • Helping organize DjangoCons in Africa, America, and Europe, and other events.
  • Hosting the documentation, source code, ticketing system, and CI system.
  • A very long tail of activities that keep the framework alive and thriving.

At the time of writing, Django is only 59% towards its annual funding goal of $300,000:

Django Software Foundation Funding Page 2024

Let's fill up that heart! 💚💚💚

Fin

May you have fun supporting Django creators and the DSF this Black Friday and Cyber Monday!

-Adam

20 Nov 2025 6:00am GMT

19 Nov 2025

feedDjango community aggregator: Community blog posts

Ansible-lint pre-commit problem + "fix"

I'm used to running pre-commit autoupdate regularly to update the versions of the linters/formatters that I use. Especially when there's some error.

For example, a couple of months ago, there was some problem with ansible-lint. You have an ansible-lint, ansible and ansible-core package and one of them needed an upgrade. I'd get an error like this:

ModuleNotFoundError: No module named 'ansible.parsing.yaml.constructor'

The solution: pre-commit autoupdate, which grabbed a new ansible-lint version that solved the problem. Upgrading is good.

But... little over a month ago, ansible-lint pinned python to 3.13 in the pre-commit hook. So when you update, you suddenly need to have 3.13 on your machine. I have that locally, but on the often-used "ubuntu latest" (24.04) github action runner, only 3.12 is installed by default. Then you'd get this:

[INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
[INFO] Installing environment for https://github.com/astral-sh/ruff-pre-commit.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
[INFO] Installing environment for https://github.com/ansible-community/ansible-lint.git.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
An unexpected error has occurred: CalledProcessError: command:
  ('/opt/hostedtoolcache/Python/3.12.12/x64/bin/python', '-mvirtualenv',
  '/home/runner/.cache/pre-commit/repomm4m0yuo/py_env-python3.13', '-p', 'python3.13')
return code: 1
stdout:
    RuntimeError: failed to find interpreter for Builtin discover of python_spec='python3.13'
stderr: (none)
Check the log at /home/runner/.cache/pre-commit/pre-commit.log
Error: Process completed with exit code 3.

Ansible-lint's pre-commit hook needs 3.10+ or so, but won't accept anything except 3.13. Here's the change: https://github.com/ansible/ansible-lint/pull/4796 (including some comments that it is not ideal, including the github action problem).

The change apparently gives a good error message to people running too-old python versions, but it punishes those that do regular updates (and have perfectly fine non-3.13 python versions). A similar pin was done in "black" and later reverted (see the comments on this issue) as it caused too many problems.

Note: this comment gives some of the reasons for hardcoding 3.13. Pre-commit itself doesn't have a way to specify a minimum Python version. Apparently old Python version cans lead to weird install errors, though I haven't found a good ticket about that in the issue tracker. The number of issues in the tracker is impressively high, so I can imagine such a hardcoded version helping a bit.

Now on to the "fix". Override the language_version like this:

- repo: https://github.com/ansible-community/ansible-lint.git
  hooks:
    - id: ansible-lint
      language_version: python3  # or python3.12 or so

If you use ansible-lint a lot (like I do), you'll have to add that line to all your (django) project repositories when you update your pre-commit config...

I personally think this pinning is a bad idea. After some discussion in issue 4821 I created a sub-optimal proposal to at least setting the default to 3.12, but that issue was closed&locked because I apparently "didn't search the issue tracker".

Anyway, this blog post hopefully helps people adjust their many pre-commit configs.

19 Nov 2025 5:00am GMT

16 Nov 2025

feedDjango community aggregator: Community blog posts

Understanding the Different POST Content Types

After more than 20 years of building for the web, this topic somehow kept slipping past me. It always felt obvious, so I never looked deeper. Recently I finally took the time to explore it properly, did some quick research, and now I'm sharing the results. Here's a simple walkthrough of the different content types you can send in POST requests.

Standard Form Data

When you submit a basic HTML form like <form method="post" action=""></form>, for example a login form, the browser sends the data using the application/x-www-form-urlencoded content type. The body of the request looks like a URL-encoded query string, the same format typically used in GET requests.

Example: username=john_doe&password=pass123.

A POST request with this content type using the fetch API looks like this:

async function sendURLEncoded() {
    const params = new URLSearchParams();
    params.append('username', 'john_doe');
    params.append('email', 'john@example.com');
    params.append('password', 'Secret123');
    params.append('bio', 'This is a multi-line\nbio text.\nIt supports newlines!');

    const response = await fetch('/api/urlencoded/', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'X-CSRFToken': getCSRFToken()
        },
        body: params
    });
    const result = await response.json();
    console.log(result);
}

On the Django side, validation with a Django form is the usual approach:

from django import forms
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from .forms import URLEncodedForm


class URLEncodedForm(forms.Form):
    username = forms.CharField(
        max_length=150,
        required=True,
        min_length=3,
    )
    email = forms.EmailField(
        required=True,
        error_messages={
            "required": "Email is required",
            "invalid": "Please enter a valid email address",
        },
    )
    password = forms.CharField(
        required=True,
        min_length=8,
    )
    bio = forms.CharField(
        required=False,
        max_length=500,
        widget=forms.Textarea,
        error_messages={"max_length": "Bio cannot exceed 500 characters"},
    )


@require_http_methods(["POST"])
def handle_urlencoded(request):
    """Handle application/x-www-form-urlencoded requests"""
    form = URLEncodedForm(request.POST)

    if not form.is_valid():
        return JsonResponse(
            {
                "status": "error",
                "errors": form.errors,
                "content_type": request.content_type,
            },
            status=400,
        )

    return JsonResponse(
        {
            "status": "success",
            "form_data": form.cleaned_data,
            "content_type": request.content_type,
        }
    )

Form Data with Files

If your form includes file uploads, the browser switches to multipart/form-data. You enable it in HTML like this:

<form method="post" action="" enctype="multipart/form-data">

A fetch-based upload looks like:

async function sendMultipart() {
    const formData = new FormData();
    formData.append('username', 'john_doe');
    formData.append('email', 'john@example.com');

    const fileInput = document.getElementById('file-input');
    if (fileInput.files[0]) {
        formData.append('avatar', fileInput.files[0]);
    }

    const response = await fetch('/api/multipart/', {
        method: 'POST',
        headers: {
            'X-CSRFToken': getCSRFToken()
        },
        body: formData
    });
    const result = await response.json();
    console.log(result);
}

The Django view works the same way, just with request.FILES added.

from django import forms
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods


class MultipartForm(forms.Form):
    username = forms.CharField(
        max_length=150,
        required=True,
        min_length=3,
    )
    email = forms.EmailField(
        required=True,
    )
    avatar = forms.FileField(
        required=False,
    )

    def clean_avatar(self):
        avatar = self.cleaned_data.get("avatar")
        if avatar:
            if avatar.size > 5 * 1024 * 1024:
                raise forms.ValidationError("File size cannot exceed 5MB")

            allowed_types = ["image/jpeg", "image/png", "image/gif", "image/webp"]
            if avatar.content_type not in allowed_types:
                raise forms.ValidationError(
                    f'Invalid file type. Allowed types: {", ".join(allowed_types)}'
                )
        return avatar



@require_http_methods(["POST"])
def handle_multipart(request):
    """Handle multipart/form-data requests (forms with files)"""
    form = MultipartForm(request.POST, request.FILES)

    if not form.is_valid():
        return JsonResponse(
            {
                "status": "error",
                "errors": form.errors,
                "content_type": request.content_type,
            },
            status=400,
        )

    form_data = {}

    for key, value in form.cleaned_data.items():
        if hasattr(value, "read"):
            form_data[key] = {
                "name": value.name,
                "size": value.size,
                "content_type": value.content_type,
            }
        else:
            form_data[key] = value

    return JsonResponse(
        {
            "status": "success",
            "form_data": form_data,
            "content_type": request.content_type,
        }
    )        

JSON String

A very common modern content type is application/json. Single-Page Applications and most JavaScript-heavy frontends rely on it.

Frontend example:

async function sendJSON() {
    const data = { 
        name: "John Doe", 
        email: "john@example.com", 
        age: 30
    };
    const response = await fetch('/api/json/', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-CSRFToken': getCSRFToken()
        },
        body: JSON.stringify(data)
    });
    const result = await response.json();
    console.log(result)
}

For validation, you can use Pydantic, which is a nice alternative to Django-REST-Framework serializers.

from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from pydantic import BaseModel, EmailStr, Field, ConfigDict, ValidationError


class JSONDataSchema(BaseModel):
    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "name": "John Doe", 
                "email": "john@example.com", 
                "age": 30,
            }
        }
    )

    name: str = Field(min_length=2, max_length=100, description="User's full name")
    email: EmailStr = Field(description="Valid email address")
    age: int = Field(ge=0, le=150, description="User's age")


@require_http_methods(["POST"])
def handle_json(request):
    """Handle application/json requests"""
    try:
        data = json.loads(request.body)
        validated = JSONDataSchema(**data)

        return JsonResponse(
            {
                "status": "success",
                "received": validated.model_dump(),
                "content_type": request.content_type,
            }
        )
    except json.JSONDecodeError:
        return JsonResponse(
            {
                "status": "error",
                "error": "Invalid JSON",
                "content_type": request.content_type,
            },
            status=400,
        )
    except ValidationError as e:
        return JsonResponse(
            {
                "status": "error",
                "errors": e.errors(),
                "content_type": request.content_type,
            },
            status=400,
        )

Newline-Delimited JSON

application/x-ndjson (or simply NDJSON) is an experimental but handy format where each line is a separate JSON object. It's useful for bulk imports - logs, analytics, and other large datasets.

async function sendNDJSON() {
    const ndjsonData = (
`{"name":"John","age":30}
{"name":"Jane","age":25}
{"name":"Bob","age":35}`
);
    const response = await fetch('/api/ndjson/', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-ndjson',
            'X-CSRFToken': getCSRFToken()
        },
        body: ndjsonData
    });
    const result = await response.json();
    console.log(result);
}

The processing logic is standard: split, parse, validate.

import json
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods


@require_http_methods(["POST"])
def handle_ndjson(request):
    """Handle application/x-ndjson requests"""
    try:
        ndjson_content = request.body.decode("utf-8")
        lines = [
            json.loads(line) for line in ndjson_content.strip().split("\n") if line
        ]

        return JsonResponse(
            {
                "status": "success",
                "lines_count": len(lines),
                "data": lines,
                "content_type": request.content_type,
            }
        )
    except json.JSONDecodeError:
        return JsonResponse({"error": "Invalid NDJSON"}, status=400)

Plain Text

Some systems accept plain text via text/plain, especially object storage services or endpoints meant for raw logs or unstructured content.

async function sendTextPlain() {
    const textData = `This is plain text content.
It can span multiple lines.
Line 3 of the content.`;

    const response = await fetch('/api/text/', {
        method: 'POST',
        headers: {
            'Content-Type': 'text/plain',
            'X-CSRFToken': getCSRFToken()
        },
        body: textData
    });
    const result = await response.json();
    console.log(result);
}

The Django view is minimal and functional:

from django.http import JsonResponse
from django.views.decorators.http import require_http_methods


@require_http_methods(["POST"])
def handle_text_plain(request):
    """Handle text/plain requests"""
    text_content = request.body.decode("utf-8")
    return JsonResponse(
        {
            "status": "success",
            "received": text_content,
            "length": len(text_content),
            "content_type": request.content_type,
        }
    )

HTML Text

You can also POST HTML content using text/html, which can be useful for wiki-style pages or HTML editors that save full documents.

async function sendHTML() {
    const htmlData = `<!DOCTYPE html>
<html>
<head><title>Example</title></head>
<body><h1>Hello World!</h1></body>
</html>`;
    const response = await fetch('/api/html/', {
        method: 'POST',
        headers: {
            'Content-Type': 'text/html',
            'X-CSRFToken': getCSRFToken()
        },
        body: htmlData
    });
    const result = await response.json();
    console.log(result);
}

The Django view would accept the data like this (add your own validation):

from django.http import JsonResponse
from django.views.decorators.http import require_http_methods


@require_http_methods(["POST"])
def handle_html(request):
    """Handle text/html requests"""
    html_content = request.body.decode("utf-8")
    return JsonResponse(
        {
            "status": "success",
            "received": html_content,
            "length": len(html_content),
            "content_type": request.content_type,
        }
    )

XML Data

Older or legacy integrations (especially SOAP-based ones) still rely on application/xml.

Here's a JavaScript example:

async function sendXML() {
    const xmlData = `<?xml version="1.0" encoding="UTF-8"?>
<user>
<name>John Doe</name>
<email>john@example.com</email>
<age>30</age>
</user>`;

    const response = await fetch('/api/xml/', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/xml',
            'X-CSRFToken': getCSRFToken()
        },
        body: xmlData
    });
    const result = await response.json();
    console.log(result);
}

And the Django view can parse the XML data into a dictionary like this:

import xml.etree.ElementTree as ET
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods


@require_http_methods(["POST"])
def handle_xml(request):
    """Handle application/xml requests"""
    try:
        xml_content = request.body.decode("utf-8")
        root = ET.fromstring(xml_content)

        data = {
            child.tag: child.text 
            for child in root
        }

        return JsonResponse(
            {
                "status": "success",
                "root_tag": root.tag,
                "data": data,
                "content_type": request.content_type,
            }
        )
    except ET.ParseError:
        return JsonResponse({"error": "Invalid XML"}, status=400)

SVG Image

SVG graphics can be sent as image/svg+xml, since they are XML-based.

async function sendSVG() {
    const svgData = `<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>`;
    const response = await fetch('/api/svg/', {
        method: 'POST',
        headers: {
            'Content-Type': 'image/svg+xml',
            'X-CSRFToken': getCSRFToken()
        },
        body: svgData
    });
    const result = await response.json();
    console.log(result);
}

The Django view (add your own validation):

from django.http import JsonResponse
from django.views.decorators.http import require_http_methods


@require_http_methods(["POST"])
def handle_svg(request):
    """Handle image/svg+xml requests"""
    svg_content = request.body.decode("utf-8")
    return JsonResponse(
        {
            "status": "success",
            "received": svg_content,
            "length": len(svg_content),
            "content_type": request.content_type,
        }
    )

Binary Data

For raw binary streams - images, audio, video, PDF, or any unknown byte sequence - the fallback is application/octet-stream.

Here is a JavaScript example of how to post it:

async function sendBinary() {
    const binaryData = new Uint8Array([72, 101, 108, 108, 111]);
    const response = await fetch('/api/binary/', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/octet-stream',
            'X-CSRFToken': getCSRFToken()
        },
        body: binaryData
    });
    const result = await response.json();
    console.log(result);
}

The Django view would be the most straightforward, because request.body is already coming as bytestring:

from django.http import JsonResponse
from django.views.decorators.http import require_http_methods


@require_http_methods(["POST"])
def handle_binary(request):
    """Handle application/octet-stream requests (raw binary data)"""
    binary_data = request.body
    return JsonResponse(
        {
            "status": "success",
            "size": len(binary_data),
            "content_type": request.content_type,
            "first_bytes": list(binary_data[:10]),
        }
    )

Protocol Buffers

Protocol Buffers use application/x-protobuf, and compared to JSON they're usually around 50% smaller and faster to parse. I won't cover the code in this article, but do your research if you need speed.

Code to Play Around with

The rough distribution of content-type usage in real-world APIs is this:

If you want to experiment with all the content types, and see the code in context, here's a repo as a great playground: https://github.com/archatas/django-post-content-types

16 Nov 2025 6:00pm GMT

14 Nov 2025

feedDjango community aggregator: Community blog posts

Django News - PyCharm 30% Promotion Extended! - Nov 14th 2025

News

Support the Django Software Foundation by buying PyCharm at a 30% Discount

The Django Software Foundation's primary fundraiser has been extended, so you can get 30 percent off PyCharm Pro and support Django until November 19.

jetbrains.com

Call for Proposals for DjangoCon US 2026 Website!

DjangoCon US 2026 requests proposals to redesign branding, illustrations, and the 11ty and Tailwind website for Chicago, including swag, signage, and starter code.

defna.org

"Boost Your GitHub DX" out now

Boost Your GitHub DX by Adam Johnson provides practical guidance on GitHub features, gh CLI, and Actions to streamline collaboration and speed software delivery.

adamj.eu

Django Software Foundation

Five ways to discover Django packages

New Django ecosystem page plus resources like State of Django survey, Django Packages, Awesome Django, Reddit and newsletters help developers discover third-party Django packages.

djangoproject.com

Django at PyCon FR 2025

Highlights from PyCon France where 27 contributors joined together in sprints, discussions of Django's direction, htmx presentations, and more.

djangoproject.com

Python Software Foundation

Trusted Publishing is popular, now for GitLab Self-Managed and Organizations

Django projects can now use PyPI Trusted Publishing to securely publish packages, with GitLab Self Managed beta support and organization pending publishers.

pypi.org

Updates to Django

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

Last week we had 14 pull requests merged into Django by 11 different contributors - including 3 first-time contributors! Congratulations to Hal Blackburn, Mehraz Hossain Rumman, and Harsh Jain for having their first commits merged into Django - welcome on board!

Fixed a bug in Django 5.2 where proxy models having a CompositePrimaryKey incorrectly raised a models.E042 system check error.

Refactored async code to use asyncio.TaskGroup for cleaner, modern concurrency management. Thank you for the hard work on this. 🎉

Django Newsletter

Sponsored Link 1

Peace of Mind for Your Django Projects

Great code doesn't keep you up at night. From maintenance to scalability, we've got your Django project under control. 🧑‍💻 Partner with HackSoft today!

hacksoft.io

Articles

Django Admin Deux: Bringing Django's Admin Back to Django

Django Admin Deux is a proof of concept admin built on Django generic class-based views, plugin-first architecture, and action-based CRUD.

has-a.blog

Preserving referential integrity with JSON fields and Django

Adds referential integrity for model references stored in JSONField within Django by registering model links and enforcing on_delete protection using django-json-schema-editor.

406.ch

Django-Tailwind v4.4: Now with Zero Node.js Setup via Standalone Tailwind CLI

Django-Tailwind 4.4 adds support for Tailwind's Standalone CLI via pytailwindcss, enabling Tailwind CSS workflows without requiring Node.js, and integrates it into manage.py.

timonweb.com

django-deadcode: idea to release in under 2 hours

django-deadcode was prototyped and published in about two hours using Agent OS and Claude to analyze Django projects for removable dead code.

softwarecrafts.co.uk

Django Fellow Report

Django Fellow Report - Natalia

A very security-heavy week . Most of my energy went into preparing and testing patches for the upcoming security release, including a tough vulnerability that I spent quite some time wrestling with. It was demanding and a bit exhausting, but everything is now on track for next week's release.

djangoproject.com

Django Fellow Report - Jacob

This week we landed the JSONNull expression I mentioned last week. We also landed a follow-up to the database delete behavior feature to add support in inspectdb.

djangoproject.com

Events

Behind the Curtain as a Conference Chair

Chairing DjangoCon US 2025 taught that effective leadership means creating and holding welcoming spaces for community, volunteers, and speakers to collaborate and thrive.

caktusgroup.com

Videos

PyBay 2025 - YouTube

PyBay 2025 features talks on Python tooling, robust testing, typing, async performance, LLM integration, and data validation relevant to Django backends.

youtube.com

The future of Python and AI with Guido van Rossum

Guido van Rossum discusses Python's role in the AI era, TypeAgent and typing tools like Pyright, and AI coding workflows with VS Code and Copilot. There are some nice Django and DjangoCon US shoutouts here.

youtube.com

Podcasts

Django Chat #189: Django 20 Years Later with Adrian Holovaty

Adrian finally agreed to come on the podcast! This episode was so much fun to record. Adrian is one of the original creators of Django and we discussed everything from initial design decisions with twenty years of hindsight, why modern JavaScript is so complicated, coding with LLMs, and much more.

djangochat.com

Django News Jobs

Looking for your next Django focused role? Here are the latest openings across security engineering, backend development, and university innovation.

Job Application for Senior Application Security Engineer at Energy Solutions - USA 🆕

Senior Python Developer at Basalt Health 🆕

Senior Back-End Developer at Showcare 🆕

Software Engineer Lead at Center for Academic Innovation, University of Michigan

Part-Time Senior Full-Stack Engineer (Python/Django) (gn) at voiio

Django Newsletter

Django Forum

DEP 15 - Improved startproject interface - Django Internals

DEP 15 standardizes and extends startproject to support multiple modern project layouts while preserving backwards compatibility and encouraging consistent, opinionated project structures.

djangoproject.com

Projects

stuartmaxwell/djcheckup

DJ Checkup is a security scanner for Django sites. This package provides a command-line interface to run the security checks against your Django site.

github.com

wsvincent/djangoforai

Django + local LLM + server side events + HTMX demo. As presented during DjangoCon US 2025 talk.

github.com


This RSS feed is published on https://django-news.com/. You can also subscribe via email.

14 Nov 2025 5:00pm GMT

How to use UUIDv7 in Python, Django and PostgreSQL

Learn how to use UUIDv7 today with stable releases of Python 3.14, Django 5.2 and PostgreSQL 18. A step by step guide showing how to generate UUIDv7 in Python, store them in Django models, use PostgreSQL native functions and build time ordered primary keys without writing SQL.

14 Nov 2025 5:00am GMT

13 Nov 2025

feedDjango community aggregator: Community blog posts

django-deadcode: idea to release in under 2 hours

A few weeks ago I noticed a toot from Jeff Triplett about Anthrophic releasing Claude Code for the Web. This was the final spark that coalesced a few different thoughts that had been lingering in the back of my head, some of I have written a bit about before. The first thought was the speed of prototyping that agentic AI enables. Essentially ideas or tasks can simply be executed rather than being written down and the time allocated to develop these ideas go from weeks to days or even hours. The second thought is related to the first in that tools like Agent OS allows for AI to build out products in a more reliable way for the most part. I have also been pondering how I can use my mobile more as an engineer, the Github app is ok for PR reviews, but to date building anything needs a larger screen.

The final thought goes back to the toot from Jeff and Claude Code on the being possibly the cloest thing so far to my post from day 282 about how our tooling doesn't yet fully leverage what AI can do for us.

Well this led to me creating two things this week. First was a template repo on Github which is only loaded with an install of my Django Agent OS profile. This enables me to quickly start a project in the browser without having to open a terminal or potentially even be at my laptop, I could start a project from my phone. Second was an experiment to see how much I could get Claude to build from the browser. I took my idea from Day 71 about analysing a Django codebase for dead code that could be removed. Over the course of about 2 hours of my time and letting Claude along with Agent OS, I have a package released on PyPI.

The unlock here is that I have yet to clone the repo to my laptop. In fact, the most time consuming part has been getting CI to work nicely to release new versions. Upon reflection this is something to go into the template repository, but then not every project needs to be uploaded to PyPI.

It's been a fun experiment to get a working proof of concept out the door so quickly, but it needs a bit more refinement, testing and review before I recommend anyone else use it! If you want to have a peak, the repo is here and package is here

13 Nov 2025 6:00am GMT

Python Leiden (NL) meetup summaries

My summaries from the sixth Python meetup in Leiden (NL).

Python and MongoDB, a perfect marriage - Mathijs Gaastra

His first experience with Mongodb was when he had to build a patient data warehouse based on literature. He started with postgres, but the fixed table structure was very limiting. Mongodb was much more flexible.

Postgres is a relational database, Mongodb is a document database. Relational: tables, clearly defined relationships and a pre-defined structure. Document/nosql: documents, flexible relationships and a flexible structure.

Nosql/document databases can scale horizontally. Multiple servers, connected. Relational databases have different scaling mechanisms.

Why is mongo such a nice combination with python?

  • The PyMongo package is great and has a simple syntax.
  • It is easily scalable
  • Documents are in BSON format ("binary json") which is simple to use and pretty efficient.

He showed example python code, comparing a mysql example with a Mongodb version. The Mongodb version did indeed look simpler.

The advantage of Mongodb (the freedom) also is its drawback: you need to do your own validation and your own housekeeping, otherwise your data slowly becomes unusable.

Mathijs is now only using Mongodb, mostly because of the speed of development he enjoys with it.

Identifying "blast beats" in music using Python - Lino Mediavilla

He showed a couple of videos of drummers. Some with and some without "blast beats". In metal (if I understood correctly) it means both a lot of base drum, but essentially also a "machine gun" on tne snare drum. He likes this kind of music a lot, so he wanted to analize it programmatically

He used the demucs library for his blast beat counter project. Demucs separates different instruments out of a piece of music.

With fourier transforms, he could analyse the frequencies. Individual drum sounds (snare drum hit, base drum hit) were analysed this way.

With the analysed frequency bits, they could recognise them in a piece of music and count occurrences and pick out the blast beats. He had some nice visualisations, too.

He was asked to analyze "never gonna give you up" from Rick Ashley :-) Downloading it from youtube, separating out the drums, ananlysing it, visualising it: it worked! Nice: live demo. (Of course there were no blast beats in the song.)

Deploying Python apps on your own infra with Github actions - Michiel Beijen

Live demo time again! He build a quick jekyll site (static site generator) and he's got a small hetzner server. Just a bit of apache config and he's got an empty directory that's being hosted on a domainname. He quickly did this by hand.

Next he added his simple code to a git repo and uploaded it to github.

A nice trick for Github actions are self hosted runners. They're easy to install, just follow the instructions on Github.

The runner can then run what's in your github's action, like "generate files with jekyll and store them in the right local folder on the server".

The runner runs on your server, running your code: a much nicer solution than giving your ssh key to Github and having it log into your server. You also can use it on some local computer without an external address: the runner will poll Github instead of it being Github that sends you messages.

The auto-deploy worked. And while he was busy with his demo, two PRs with changes to the static website had already been created by other participants. He merged them and the site was indeed updated right away.

13 Nov 2025 5:00am GMT

12 Nov 2025

feedDjango community aggregator: Community blog posts

Django 20 Years Later - Adrian Holovaty

🔗 Links

🎥 YouTube

Sponsor

This episode was brought to you by HackSoft, your development partner beyond code. From custom software development to consulting, team augmentation, or opening an office in Bulgaria, they're ready to take your Django project to the next level!

https://www.hacksoft.io/solutions/django

12 Nov 2025 6:00pm GMT

Behind the Curtain as a Conference Chair

This post is the first in a three-part series reflecting on DjangoCon US 2025 - In this post, I'm taking you behind the scenes of DjangoCon US 2025 to share what it taught me about leadership, community, and the power of holding space for others.

12 Nov 2025 12:00pm GMT