Recent Posts

See also posts by tag or search with DuckDuckGo:

Python: introducing tprof, a targeting profiler

Profilers measure the performance of a whole program to identify where most of the time is spent. But once you’ve found a target function, re-profiling the whole program to see if your changes helped can be slow and cumbersome. The profiler introduces overhead to execution and you have to pick out the stats for the one function you care about from the report. I have often gone through this loop while optimizing client or open source projects, such as when I optimized Django’s system checks framework (previous post).

Read more...

Django Quiz 2025

Last month, I held another quiz at the December edition of Django London. The December quiz is an annual tradition at our meetup, a way of making this final event of the year more relaxed and giving away some nice prizes. This was the seventh quiz that I’ve presented, and the eighth overall.

Read more...

Django: implement HTTP basic authentication

Previously, we covered bearer authentication within HTTP’s general authentication framework. In this post, we’ll implement basic authentication, where the client provides a username and password.

Read more...

Django: what’s new in 6.0

Django 6.0 was released today, starting another release cycle for the loved and long-lived Python web framework (now 20 years old!). It comes with a mosaic of new features, contributed to by many, some of which I am happy to have helped with. Below is my pick of highlights from the release notes.

Read more...

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.

Read more...

GitHub: top commands in gh, the official GitHub CLI

gh (pronounced… “guh”?) is GitHub’s official command line interface (CLI) tool. It lets you interact with GitHub directly from the command line, supporting most key features across more than 25 commands and over 200 subcommands. It’s also great for bridging the terminal-browser gap, allowing you to jump to pages relevant to your current context, such as the PR for the current branch.

Read more...

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.

Read more...

“Boost Your GitHub DX” out now

My new book, Boost Your GitHub DX is out now!

Read more...

Django: Introducing django-http-compression

HTTP supports response compression, which can significantly reduce the size of responses, thereby decreasing bandwidth usage and load times for users. It’s a cheap and valuable technique for improving website performance.

Read more...

Django: Introducing django-watchfiles, for more efficient runserver autoreloading

Django’s runserver automatically reloads when you change Python files. Without this autoreloading feature, you’d need to manually restart the server every time you made a code change.

Read more...

Git: partially cherry-pick a commit

git cherry-pick allows you to copy a commit another branch to your current one. A common use case is copying a bug fix from a long-running feature branch to another one, so that it can be merged sooner, for example:

Read more...

Git: check if a commit exists on a given branch

To check if a commit SHA exists on a given branch, you have a couple of options.

Read more...

Python: fix SyntaxWarning: 'return' in a 'finally' block

Take this code:

Read more...

Python: capture stdout and stderr in unittest

When testing code that outputs to the terminal through either standard out (stdout) or standard error (stderr), you might want to capture that output and make assertions on it. To do so, use contextlib.redirect_stdout() and contextlib.redirect_stderr() to redirect the respective output streams to in-memory buffers that you can then inspect and assert on.

Read more...

Git: count files in a repository

When you want to count the number of files within a Git repository, it's generally best to use Git itself for the task because it will skip over any generated or downloaded files. Here is a command chain to use to count all committed files within the current directory:

Read more...

Django: write a custom URL path converter to match given strings

Here’s a little tip based on some recent work. The project has a URL pattern where the first part of the URL matches the current role the user is viewing the site as. Let’s say the roles are “chef”, “gourmand”, and “foodie”—example URLs might look like this:

Read more...

Python: check a package version with importlib.metadata.version()

Sometimes, it’s useful to branch the behaviour of your code based on the version of a package that you have installed. This may be to support an upgrade in your project, or for your own package to support different versions of a dependency.

Read more...

Django: split ModelAdmin.get_queryset() by view

Within Django’s popular admin site, you can override ModelAdmin.get_queryset() to customize the queryset used by the admin views. It’s often used for performance optimizations, such as adding a select_related() call to batch-fetch related objects:

Read more...

Django: iterate through all registered URL patterns

I’ve found it useful, on occasion, to iterate through all registered URL patterns in a Django project. Sometimes this has been for checking URL layouts or auditing which views are registered.

Read more...

Git: find the largest commits

Recently, I was working in a new repository and found the git blame output often pointed back to a large repository-wide formatting commit (applying Black to all Python files). To ignore this commit in git blame, I added its SHA to a .git-blame-ignore-revs file, per this documentation:

Read more...

Python: fix BrokenPipeError when piping output to other commands

If you’ve written a Python script that outputs a lot of data, then piped that output into another command that only reads part of it, you might have encountered a BrokenPipeError. For example, take this script:

Read more...

Git: share a full repository as a file with git fast-export

Typically, we share repositories through a Git host, like GitHub, allowing others to clone the repository to get a copy. But sometimes that’s not an option, for example when trying to get someone started on your project when corporate onboarding processes take days to grant GitHub access.

Read more...

Django: hide the development server warning

From Django 5.2 (April 2025), the runserver management command outputs a warning:

Read more...

Django: Introducing inline-snapshot-django

I recently released a new package called inline-snapshot-django. It’s a tool for snapshot testing SQL queries in Django projects, described shortly.

Read more...

Python: sharing common tests in unittest

A neat testing pattern is writing common tests in a base class and then applying them to multiple objects through subclassing. Doing so can help you test smarter and cover more code with less boilerplate.

Read more...