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 💡