7 simple examples using Django GeneratedField ⚡️

Photo of Tom Dekan
by Tom Dekan

A feature added in Django 5.0 is GeneratedField, which allows us to auto-calculate database fields.

Below are 7 short examples. After looking at them, you'll know how to use GeneratedField to use the database to do calculations for you neatly and extremely quickly.

I've made an optional video guide (featuring me 🏇🏿) here, describing the problem and solution:

In the below examples using GeneratedField, we will automatically calculate:

  • A person's full name and initials
  • The day of the week and whether it's a weekend.
  • Exchange rates for a financial asset
  • Employee duration of service
  • Discounts based on purchase quantity
  • Body mass index (BMI) (i.e., math operations)
  • Compound interest (i.e., financial calculations)

For each, we'll:

a) add the model to models.py, and

b) query the model to show how the calculated field is used.

Let's get started 🚀

Setup Django and our app

  • Install packages and create our Django app.
  • Django must be >= 5.0, which requires Python >= 3.10.
pip install django 
django-admin startproject core .
python manage.py startapp sim
  • Check your Django version.
python -m django --version

You should see >= 5.0.

  • Add our app sim to the INSTALLED_APPS in settings.py:
# settings.py
INSTALLED_APPS = [
  'sim',
  ...
]

Example 1: Get a person's full name and initials

Next up, here's an example of how to use GeneratedField to automatically concatenate strings from different fields.

  • Add the below model to sim/models.py:
from django.db import models
from django.db.models.functions import Substr, Concat


class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    full_name = models.GeneratedField(
        expression=Concat('first_name', models.Value(' '), 'last_name'),
        output_field=models.CharField(max_length=100),
        db_persist=True
    )
    initials = models.GeneratedField(
        expression=Concat(
            Substr('first_name', 1, 1), Substr('last_name', 1, 1)),
        output_field=models.CharField(max_length=2),
        db_persist=True
    )

  • Run the migration:
python manage.py makemigrations
python manage.py migrate
  • Add a few people to the database:
from sim.models import Person
Person.objects.create(first_name='Robert', last_name='Katz')
Person.objects.create(first_name='Alexander', last_name='Henry')
  • Query the model to show the full names and initials:
Person.objects.all().values('full_name', 'initials')

>>> <QuerySet [{'full_name': 'Robert Katz', 'initials': 'RK'}, {'full_name': 'Alexander Henry', 'initials': 'AH'}]>

Example 2: Calculate the day of the week and whether it's a weekend

Here's a simple example, which would have been very useful for when I was building schedules and calendars for one of my previous startups (HR tech). I used a combination of app code and fairly complex SQL to do date calculations. GeneratedField simplifies this a lot.

Let's build it 👷:

  • Add the below model to sim/models.py:
from django.db import models
from django.db.models.functions import Extract


class Event(models.Model):
    start_time = models.DateTimeField()
    day_of_week = models.GeneratedField(
        expression=Extract('start_time', 'week_day'),
        output_field=models.IntegerField(),
        db_persist=True
    )
    is_weekend = models.GeneratedField(
        expression=models.Case(
            models.When(day_of_week__in=[1, 7], then=True),
            default=False,
            output_field=models.BooleanField(),
        ),
        db_persist=True,
        output_field=models.BooleanField(),
    )


  • Run the migration:
python manage.py makemigrations
python manage.py migrate
  • Add a few events to the database:
from sim.models import Event
from datetime import datetime
Event.objects.create(start_time=datetime(2022, 1, 1, 12, 0, 0)) # Saturday.
Event.objects.create(start_time=datetime(2022, 1, 2, 12, 0, 0)) # Sunday. 
Event.objects.create(start_time=datetime(2022, 1, 3, 12, 0, 0)) # Monday.
  • Query the model to show the calculated field:
Event.objects.all().values('day_of_week', 'is_weekend')

>>> QuerySet [{'day_of_week': 7, 'is_weekend': True}, {'day_of_week': 1, 'is_weekend': True}, {'day_of_week': 2, 'is_weekend': False}]>

Note that SQL databases use 7 for Saturday, 1 for Sunday. So, 2 is Monday.

Example 3: Calculate exchange rates for a financial asset

Next up, here's an example of how to use GeneratedField to calculate exchange rates automatically. This would have been useful for me when I was building a hedge fund's infrastructure.

Add the Model to Your Django App

  • Update sim/models.py with the following model:
from django.db import models

class Asset(models.Model):
    ticker = models.CharField(max_length=10)
    price_eur = models.DecimalField(max_digits=10, decimal_places=2)
    eur_to_usd_exchange_rate = models.DecimalField(max_digits=5, decimal_places=2, default=1.1)
    price_usd = models.GeneratedField(
        expression=models.F("price_eur") * models.F("eur_to_usd_exchange_rate"),
        output_field=models.DecimalField(max_digits=12, decimal_places=2),
        db_persist=True
    )

Migrations

  • Run migrations to update the database schema:
python manage.py makemigrations
python manage.py migrate

Add Data and Query

  • Insert products into the database:
from sim.models import Asset
Asset.objects.create(ticker='MSFT', price_eur=121.32, eur_to_usd_exchange_rate=1.1)
Asset.objects.create(ticker='GOOG', price_eur=2.23, eur_to_usd_exchange_rate=1.1)
  • Query to see the calculated USD price:
Asset.objects.all().values('ticker', 'price_eur', 'price_usd')

>>> <QuerySet [{'ticker': 'MSFT', 'price_eur': Decimal('121.32'), 'price_usd': Decimal('133.45')}, {'ticker': 'GOOG', 'price_eur': Decimal('2.23'), 'price_usd': Decimal('2.45')}]>

Example 4: Calculate employee duration of service

This shows how to use GeneratedField to calculate the duration of service for employees. Another example that would have been useful for me when building a previous product in HR tech to calculate employee length of service.

Add the Model to Your Django App

  • Update sim/models.py with:
from django.db import models


class Employee(models.Model):
    hire_date = models.DateField()
    most_recent_work_date = models.DateField(null=True)
    service_period = models.GeneratedField(
        expression=models.F('most_recent_work_date') - models.F('hire_date'),
        output_field=models.DurationField(),
        db_persist=True
    )
  • Run the migrations:
python manage.py makemigrations
python manage.py migrate

Add Data and Query

  • Add an employee and find their years of service:
from sim.models import Employee
from datetime import date

Employee.objects.create(hire_date=date(2010, 1, 1), most_recent_work_date=date(2030, 2, 1))
Employee.objects.create(hire_date=date(2026, 1, 10), most_recent_work_date=date(2026, 3, 2))
Employee.objects.values('hire_date', 'service_period')

>>> <QuerySet [{'hire_date': datetime.date(2010, 1, 1), 'service_period': datetime.timedelta(days=7336)}, {'hire_date': datetime.date(2026, 1, 10), 'service_period': datetime.timedelta(days=51)}]>

Example 5: Calculate discounts based on purchase quantity

Add the Model to Your Django App

  • Update sim/models.py with:
from django.db import models
from django.db.models import Case, When, Value, BooleanField


class Order(models.Model):
    quantity = models.IntegerField()
    unit_price = models.DecimalField(max_digits=10, decimal_places=2)
    discount_per_unit = models.GeneratedField(
        expression=Case(
            When(quantity__gt=100, then=models.F("unit_price") * 0.1),
            default=Value(0),
            output_field=models.DecimalField(max_digits=12, decimal_places=2)
        ),
        db_persist=True,
        output_field=models.DecimalField(max_digits=12, decimal_places=2),
    )
    total_price = models.GeneratedField(
        expression=(models.F("quantity") * models.F("unit_price")) -
                   (models.F("quantity") * models.F("discount_per_unit")),
        output_field=models.DecimalField(max_digits=12, decimal_places=2),
        db_persist=True
    )
  • Run the migrations:
python manage.py makemigrations
python manage.py migrate

Add Data and Query

  • Add orders to your database and query for discounts:
from sim.models import Order

Order.objects.create(quantity=150, unit_price=10)
Order.objects.create(quantity=50, unit_price=10)
Order.objects.all().values()

>>> <QuerySet [{'id': 1, 'quantity': 150, 'unit_price': Decimal('10.00'), 'discount_per_unit': Decimal('1.00'), 'total_price': Decimal('1350.00')}, {'id': 2, 'quantity': 50, 'unit_price': Decimal('10.00'), 'discount_per_unit': Decimal('0.00'), 'total_price': Decimal('500.00')}]>

Example 6: Calculate Body Mass Index (BMI)

Add the Model to Your Django App

  • Update sim/models.py with:
class Patient(models.Model):
    weight_kg = models.FloatField()
    height_m = models.FloatField()
    bmi = models.GeneratedField(
        expression=models.F('weight_kg') / (models.F('height_m') * models.F('height_m')),
        output_field=models.FloatField(),
        db_persist=True
    )
  • Run the migrations:
python manage.py makemigrations
python manage.py migrate

Add Data and Query

  • Add patient data to your database and query for BMI:
from sim.models import Patient

Patient.objects.create(weight_kg=70, height_m=1.75)
Patient.objects.all().values('bmi')

>>> <QuerySet [{'bmi': 22.857142857142858}]>

Example 7: Calculate compound interest

Most people like the thought of their money growing exponentially. Here's an example of how to use GeneratedField to calculate compound interest.

Add the Model to Your Django App

  • Update sim/models.py with:
from django.db import models
from django.db.models.functions import Power


class Investment(models.Model):
    principal_amount = models.DecimalField(max_digits=10, decimal_places=2)
    annual_interest_rate = models.FloatField()
    years = models.IntegerField()
    future_value = models.GeneratedField(
        expression=models.ExpressionWrapper(
            models.F('principal_amount') * Power(models.F('annual_interest_rate') + 1, models.F('years')),
            output_field=models.DecimalField(max_digits=15, decimal_places=2)
        ),
        db_persist=True,
        output_field=models.DecimalField(max_digits=15, decimal_places=2),
    )
  • Run the migrations:
python manage.py makemigrations
python manage.py migrate

Add Data and Query

  • Add investment data to your database and calculate the future value:
from sim.models import Investment

Investment.objects.create(principal_amount=1000, annual_interest_rate=0.05, years=10)
Investment.objects.all().values('future_value')

>>> <QuerySet [{'future_value': Decimal('1628.89')}]>

Congrats - you now know how to use GeneratedField in Django 🎉

This is a powerful tool to simplify your code by moving calculations easily to the database, wrapped in the simple interface of the Django ORM.

P.S - Build your Django frontend even faster

I want to release high-quality products as soon as possible. Probably like you, I want to make my Django product ideas become real as soon as possible.

That's why I built Photon Designer - an entirely visual editor for building Django frontend at the speed that light hits your eyes. Photon Designer outputs neat, clean Django templates 💡

Let's get visual.

Do you want to create beautiful frontends effortlessly?
Click below to book your spot on our early access mailing list (as well as early adopter prices).
Copied link to clipboard 📋

Made with care by Tom Dekan

© 2024 Photon Designer