| published by | Tim Schilling |
|---|---|
| in blog | Better Simple |
| published date | 2026-07-02 |
| original entry | Nifty Django Feature: F Expressions |
A nifty feature in Django is the F expression. The F stands for Field, and they are used to make references to other fields on the model in queries to the database. They can be used on both the read and write side of things. These provide a lot of utility and can help avoid race conditions when saving model changes.
The F expression can be used everywhere on the read side. You can use it in .filter(), .annotate() and even .order_by().
Here’s an example of using F in a filter where we want to find pets that are starving by seeing which need more treats than they’ve been given.
from django.db import models
from django.db.models import F
class Species(models.Model):
name = models.CharField(max_length=100)
class Pet(models.Model):
species = models.ForeignKey(Species, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
treats_needed = models.IntegerField()
treats_given = models.IntegerField()
last_given_treats = models.DateTimeField(null=True)
def get_starving_pets():
"""Find the pets who are _STARVING_"""
return Pet.objects.filter(
treats_needed__gt=F("treats_given")
)
It’s possible to traverse model relationships inside the F expression as well.
In this example, we see the model relationships being traversed on both the left-hand side and right-hand side in the .filter() call of find_specialized_appointments(). The right hand side being the F expression.
from django.db import models
from django.db.models import F
from my_app.models import Pet, Species
class Vet(models.Model):
specialty = models.ForeignKey(Species, on_delete=models.CASCADE)
class Appointment(models.Model):
vet = models.ForeignKey(Vet, on_delete=models.CASCADE)
pet = models.ForeignKey(Pet, on_delete=models.CASCADE)
def find_specialized_appointments():
"""Find appointments where the vet specializes in the pet's species."""
return Appointment.objects.filter(
vet__specialty=F("pet__species")
)
It’s also possible to select a single field from a related model and annotate it to the QuerySet. In this example, we’re annotating the pet’s name on the appointment.
def appointments_with_pet_name():
return Appointment.objects.all().annotate(
pet_name=F("pet__name")
)
Doing so allows us to use appointment_instance.pet_name rather than appointment_instance.pet.name. This is a niche optimization that should only be considered when dealing with large quantities of data or if Pet had dozens of fields on it.
The F expression is also how we customize ordering in .order_by(). In this example, we are sorting pets so that those that haven’t been given treats (last_given_treats is None), are first, then those who were given treats longest ago, with those who were given treats recently being last.
def order_pets_by_last_treat():
"""
Sort pets never given treats first, then oldest treat to most recent.
"""
return Pet.objects.order_by(
F("last_given_treats").asc(nulls_first=True)
)
The F expression can be used in writes to the database as well. Using an F expression allows the query to reference a column so the computation happens in the database, not in Python. It’s especially useful here when dealing with race conditions where another process or request may be updating the same data.
Typically, when model_instance.save() is called, the values on the model instance will be written to the database exactly as they are. For example:
pet = Pet.objects.filter(treats_given=0).first()
# Wait a minute while we feed a treat to our pet
pet.treats_given += 1
pet.save()
For the pet that was returned, it will write a value of 1 to the table for the treats_given column. However, if while we’re waiting to feed a treat to the pet, another process also feeds a treat to the pet and updates the table’s value from a 0 to 1, we would want to write 2 rather than 1. This is because we should be incrementing the value.
Though when we increment, we want to increment the value that’s in the table, not the value that’s in memory (our pet instance). Here’s how you use an F expression to do just that.
pet = Pet.objects.filter(treats_given=0).first()
# Wait a minute while we feed a treat to our pet
pet.treats_given = F("treats_given") + 1
pet.save()
We can also do this same thing using the .update() QuerySet method.
Pet.objects.all().update(treats_given=F("treats_given") + 1)
The Django documentation is extensive on this topic. There are several more ways you can use F expressions, but they are relatively intuitive once you understand that the F expression is a programmatic way to reference fields on a model in a query.
You can find more information in two areas:
If you have thoughts, comments, or questions, please let me know. You can set up a meeting with me, or find me on the Fediverse, Django Discord server or use email.