Subscribe to my blog| Johnny Metz
Johnny Metz's personal website and blog| Johnny Metz
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...| Posts on Johnny Metz
In a Django application, fetching the latest record for each group is a common yet challenging task, especially when working with large datasets. Whether you’re building an analytics dashboard or managing grouped data, finding an efficient solution is key. In this blog post, we’ll explore five different approaches to tackle this problem, ranked from least to most effective based on performance and readability, using the following Book model: classBook(models.Model): title = models.CharFie...| Posts on Johnny Metz
Preventing downtime during deployments is crucial for maintaining service availability and ensuring a positive user experience. Blue-green deployments have emerged as a popular strategy to achieve this goal. However, they introduce challenges, especially when dealing with database changes. This article delves into what blue-green deployments are, why database changes can be tricky in this context, and how to navigate common change scenarios effectively in Django. Blue-Green Deployments A blue...| Posts on Johnny Metz
Background As software engineers, one of the most crucial skills we develop is the ability to search through code efficiently. Whether it’s finding a specific function, understanding how a certain feature is implemented, or tracing a bug, being able to quickly navigate a codebase is essential for productivity. However, many codebases can be complex and sprawling, leading to noisy search results that hinder rather than aid our progress. JetBrains provides a few tools to help you refine your ...| Posts on Johnny Metz
Optimizing Django query performance is critical for building performant web applications. Django provides many tools and methods for optimizing database queries in its Database access optimization documentation. In this blog post, we will explore a collection of additional and essential tips I’ve compiled over the years to help you pinpoint and resolve your inefficient Django queries. Kill Long-Running Queries with a Statement Timeout PostgreSQL supports a statement_timeout parameter that a...| Posts on Johnny Metz
Introduction When building a Django application, one of the key challenges developers face is optimizing database query performance. Django provides two tools,select_related and prefetch_related, that reduce the number of database queries, and increase the performance of your application. This blog post explores the power of these two methods and how to combine them to maximize your application’s query performance. My team at PixieBrix implemented these techniques and have seen a significan...| Posts on Johnny Metz
Docker is a platform for developing, shipping and running applications in isolated, lightweight and portable containers. It is a critical part of a developer’s toolbelt and one I use just about everyday. Docker can consume a large amount of disk space. Per the Docker documentation: Docker takes a conservative approach to cleaning up unused objects (often referred to as “garbage collection”), such as images, containers, volumes, and networks: these objects are generally not removed unles...| Posts on Johnny Metz
See the post here: Sort a Django Queryset by a Custom Order| Posts on Johnny Metz
On a development team, you never want to push directly to the main branch. Instead, you want to require changes to be made through pull requests so they can be properly reviewed by other developers. Some developers, including myself, occasionally forget to push to a new branch so I like to have an automated check to prevent this mistake. Here are two methods to block direct pushes to the GitHub main branch.| Posts on Johnny Metz
See the post here: Using Hadolint, a Dockerfile linter, To Enforce Best Practices| Posts on Johnny Metz
See the source code for a working example. Next.js is a popular React Framework that comes with a lot of great features such as hybrid static & server rendering, smart bundling, file system routing, and much more. I prefer it over vanilla React. When we dockerize a Next.js application, we want the final production and development images to be small, fast to build and easy to maintain. Let’s see how we can use multi-stage builds and other image optimization techniques to create the ideal ima...| Posts on Johnny Metz
See the source code for a working example. UI testing is a critical part of any modern web application. My favorite testing framework is Cypress which enables you to write clean, fast and reliable tests. It consists of two main commands: cypress run: Runs Cypress tests from the CLI without a GUI. Used mostly in CI/CD. cypress open: Opens Cypress in an interactive GUI. Used for local development. I like to dockerize my entire application so it can be run anywhere (my machine, coworker’s mach...| Posts on Johnny Metz
You can use watchman in your Django project to make auto-reloads more CPU efficient. Adam Johnson’s Efficient Reloading in Django’s Runserver With Watchman blog post does an excellent job describing how to set this up. I highly recommend giving it a read. The tutorial explains how to install watchman on macOS with brew install watchman but does not explain how to install it in a Python docker container. Considering all of my Django projects are dockerized, I decided to figure it out.| Posts on Johnny Metz
In Django, you can define a set of choices for any field. If you’re using a SPA frontend, such as React or Vue, then you’ll need to access these choices in a form. Let’s look at two ways to do this. As an example, we’ll use the following Device model: classDevice(models.Model): classSize(models.TextChoices): SMALL ="S" MEDIUM ="M" LARGE ="L" name = models.CharField(max_length=255) size = models.CharField(max_length=255, choices=Size.choices) Hardcode choices in frontend The fastest ap...| Posts on Johnny Metz
In Django, a related object is a model instance used in the one-to-many or many-to-many context. For example, let’s look at the built-in User model, which has a many-to-many relationship with the Group model. classUser(models.Model): groups = models.ManyToManyField(Group, related_name="groups") For any given User object, all linked Group objects are called “related objects”. Here are 5 ways to fetch all User objects with at least one related Group object. Iterate over each object in Pyt...| Posts on Johnny Metz
The Django ORM is a powerful tool but certain aspects of it are counterintuitive, such as the SQL order of execution. Let’s look at an example of this trap and how we can fix it using subqueries: classBook(models.Model): classMeta: constraints = [ models.UniqueConstraint( fields=["name", "edition"], name="%(app_label)s_%(class)s_unique_name_edition", ) ] name = models.CharField(max_length=255) edition = models.CharField(max_length=255) release_year = models.PositiveIntegerField(null=True) I...| Posts on Johnny Metz
Keeping your models in sync with your migrations is an important part of any Django app. My team and I frequently make changes to our models and we occassionally forget to create new migrations for those changes. This results in errors and data loss. Let’s look at an easy way to ensure your models and migrations are always in sync: We’ll use a simple Product model. classProduct(models.Model): name = models.CharField(max_length=255) Let’s say we want to add a quantity field.| Posts on Johnny Metz
Johnny Metz's personal website and blog| Johnny Metz
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 time...| Johnny Metz