Welcome to my blog

Django Time-Based Lookups: A Performance Trap

Django’s field lookups are one of the ORM’s best features, but time-based lookups can quietly bypass database indexes, turning fast queries into expensive full table scans. A Slow Production Query I ran into this while debugging a 30 second query on a large table (~25 million rows): class Event(models.Model): timestamp = models.DateTimeField(db_index=True) Event.objects.filter(timestamp__date=datetime.date(2026, 1, 5)).count() It generates SQL like this: SELECT COUNT(*) FROM event WHERE timestamp::date='2026-01-05'; At first glance, it looked totally reasonable — a simple filter on an indexed field. But after checking the query plan, I discovered the issue: the query can’t use the index and falls back to a full table scan because it casts the field to a date. ...

January 19, 2026

Avoiding Duplicate Objects in Django Querysets

When filtering Django querysets across relationships, you can easily end up with duplicate objects in your results. This is a common gotcha that happens with both one-to-many (1:N) and many-to-many (N:N) relationships. Let’s explore why this happens and the best way to avoid it. The Problem When you filter a queryset by traversing a relationship, Django performs a SQL JOIN. If a parent object has multiple related objects that match your filter, the parent object appears multiple times in the result set. ...

January 3, 2026

7 Heroku Features Every Developer Should Be Using

Heroku makes hosting simple, but most developers overlook its advanced capabilities. After years of running apps on the platform, I’ve found several underrated features that speed up your workflow and make your apps more reliable. Here are seven you shouldn’t miss. 1. Preboot Preboot spins up new dynos and starts routing traffic to them before the old ones are terminated. The result is seamless, zero-downtime deployments. The tricky part is knowing when the cutover is complete, since the Heroku dashboard doesn’t show it. Use this command to confirm when the new dynos are live: ...

September 13, 2025

The Django db_default Gotcha That Breaks Your Code

Starting in Django 5.0, you can use db_default to define database-level default values for model fields. It’s a great feature but comes with a subtle and dangerous gotcha that can silently break your code before the object is ever saved. The Gotcha in Action Let’s say you’re building a simple task manager, and you want to track whether a task is completed: from django.db import models class Task(models.Model): is_completed = models.BooleanField(db_default=False) The db_default option ensures the database applies the default in raw INSERT queries and prevents errors during a rolling deployment. ...

August 3, 2025

Stop Using Django's squashmigrations: There's a Better Way

Squashing merges multiple database migrations into a single consolidated file to speed up database setup and tidy up history. Django’s squashmigrations command promises to handle this, but it’s error-prone and unnecessarily complex. A clean reset is faster and simpler. ⚠️ Why squashmigrations Falls Short Broken in Practice In medium-to-large projects, I’ve consistently seen squashmigrations generate poor results, such as failing to optimize basic no-ops (like adding and deleting the same field) and even breaking migrations. The official docs acknowledge this: ...

July 26, 2025