Welcome to my blog

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

Speed Up Django Queries with values() over only()

If your Django queries feel slow, the problem might not be your database — it might be your ORM. Recently, I was working with a query that took 25 seconds to run through the Django ORM, but the underlying SQL completed in just 2 seconds. With a single change, I got the ORM query down to 2 seconds as well — and reduced the memory footprint by 70%. Let’s walk through what happened, and why using .values() instead of .only() can dramatically improve performance. ...

June 29, 2025

Avoiding PostgreSQL Pitfalls: The Hidden Cost of Failing Inserts

A simple insert query turned into a silent performance killer. Our frontend pings our server every few minutes to track device activity. Each ping attempts to insert a row into a DevicePingDaily table, which has a unique constraint on (device_id, date) to ensure only one record per device per day. In Django, the logic looked like this: try: DevicePingDaily.objects.create(device=device, date=today) except IntegrityError: pass It seemed harmless. But as traffic grew, latency spiked and API timeouts increased. Observability tools quickly pointed to the culprit: ...

June 15, 2025

Disable Redundant Gunicorn Access Logs on Heroku

When hosting an application on Heroku, managing logs efficiently is crucial for maintaining system health and keeping costs down. Heroku provides built-in logging for all incoming requests, but by default, Gunicorn, the Python HTTP server often used in Heroku deployments, also logs incoming requests. This duplication can clutter your logs, making them harder to parse and more expensive to store. Let’s explore why this redundancy exists and how to fix it. Heroku Router Logs Heroku’s Router automatically logs all incoming HTTP requests, providing a wealth of data for monitoring and debugging your application. These logs are always enabled and include detailed information, such as the HTTP method and URL path of the request, the response status code, the client’s IP address, and the request processing time (see Heroku Router Log Format). ...

November 25, 2024