Django Generated Fields

December 5, 2023 (1y ago)

Table of Contents

Django, just released its new major version, django 5.0, and one of the features that gained everyone's eyes is GeneratedField. Remember model managers, that we used to apply business logic to database fields? GeneratedFields are like that. You can use them to get business logic to database layer which is most of times - the lowest level of your app.

You can try out django 5.0 by installing it with the following command - python3 -m pip install django==5.0rc1

⚠️

If you want to try Django 5.0 or its upcoming version, you would want to have python>=3.10 in your system. Django 4.2.x was the last series to support python 3.8 and 3.9. See more about it here

GeneratedField's lore

Earlier we used methods inside our models to filter common business queries in our model itself, like this:

from  django.db import models
 
class Post(models.Model):
	title = models.CharField(max_length=70)
	# ...
	
	def get_howto_guides(self):
		return Post.objects.filter(title__istartswith="how to")

or we can use Managers like this,

from django.db import models
 
class HowtoPostsManager(models.Manager):
	def get_queryset(self):
		return super().get_queryset().filter(title__istartswith="how to")
		# istartswith lookup field is used to
		# lookup case-insensitive titles.
		
class Post(models.Model):
	# ...
	objects = models.Manager() # Default Manager
	how_to = models.HowtoPostsManager() # our custom manager

Now Post.objects.all(), will return all the posts from the database, while Post.how_to.all(), will return only posts whose title starts with “How to”.

Now GeneratedField comes into play. Look at this scenario where there is a model named Booking.

from django.db import models
 
class Booking(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()

Here if I want to calculate the total duration of Booking, I will implement it like this,

from django.db import models
 
class Booking(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()
 
    def duration(self):
        return self.end_date - self.start_date

Or, I can use a model manager, like this,

from django.db import models
from django.db.models import F
 
class DurationManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().annotate(duration=F("end_date")-F("start_date"))
 
class Booking(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()
    objects = DurationManager()
💡

But, with both of these options, the field duration doesn't exist on database, so I can't index it. This is where GeneratedField comes in.

I can use GeneratedField to create a field duration on my Booking model, which will be kept up-to-date automatically by database. I can also choose to persist this in the database, which means I can index it.

from django.db import models
from django.db.models import F
 
class Booking(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()
    duration = models.GeneratedField(
        expression=F("end_date")-F("start_date"),
        output_field=models.DurationField(),
        db_persist=True
    )

TL;DR

GeneratedField is a new Django 5.0 feature and has these characteristics:

  • Its value is calculated entirely by the database
  • It works in all supported backend databases

GeneratedField

The GeneratedField are full-fledged fields that can be used in queries, displayed and even indexed but their values cannot be set or modified because they are automatically calculated by the database itself whenever the other fields of the same row are modified.

For this reason, they are very useful for having immediately available values calculated starting from the other fields of the same model as long as these are in the same database table.

The definition of the GeneratedField class requires specifying the expression, output_field, and db_persist attributes.

Attributes

  • db_persist - True|False - If set to True, it will occupy database storage as if it were a real column. Can be used for indexing.
  • output_field - An explicit model field instance to define the generated fields datatype and its other attributes. Eg: FloatField, DateField, DurationField etc.
  • expression - The expression that the database will evaluate to automatically set the field value each time the model is changed.
You might use GeneratedField if...
You want to bring a lot of logic back into database
Simplify the collaboration of different application on same database

References

Further Reading


Rick SanchezFavicon by Icons8

Design Template by Lee Robinson