New

Experience Smart HR with Horilla Mobile App

Google Play Store Google Play Store
Home / Blogs

How Django Generative Fields Simplify Database Operations

Django
·

May 18, 2026

how-django-generative-fields-simplify-database-operations

There is a category of fields in a database that you never want to calculate manually at query time. Things like a full name derived from first and last name, a total price calculated from quantity and unit price, or a slug generated from a title. In older Django patterns, you would either store these as regular fields and keep them in sync through signals or overridden save methods, or you would calculate them in Python every time you needed them. Both approaches have tradeoffs. Django’s GeneratedField, introduced in Django 5.0, offers a cleaner solution by pushing the computation down to the database itself.

Thank you for reading this post, don't forget to subscribe!

What Is a GeneratedField?

A GeneratedField is a model field whose value is always computed from other fields in the same row, using a database-level expression. The value is never set by application code — the database calculates it automatically whenever a row is inserted or updated.

This mirrors what relational databases call generated columns, a feature supported in PostgreSQL, MySQL, MariaDB, and SQLite (with some variation). Django’s GeneratedField is the ORM-level abstraction that lets you define these columns in a standard Django model without writing raw SQL.

The Two Types: STORED and VIRTUAL

Django’s GeneratedField supports two modes, controlled by the db_persist argument:

STORED (db_persist=True): The computed value is physically stored in the database table alongside the other columns. It is calculated when the row is written and stored as a real value. Reading it is fast because no computation happens at read time. This is the equivalent of a STORED generated column in SQL.

VIRTUAL (db_persist=False): The value is computed on the fly every time the row is read. It is never stored on disk. This saves storage space but adds a small computation cost on every read. Not all databases support virtual generated columns — SQLite does not, for example.

A Simple Example

Say you have a model for products and want to keep a discounted_price field that is always 10% off the regular price:

from django.db import models
from django.db.models import F, ExpressionWrapper, DecimalField

class Product(models.Model):
    name = models.CharField(max_length=200)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    discounted_price = models.GeneratedField(
        expression=ExpressionWrapper(
            F("price") * 0.9,
            output_field=DecimalField(max_digits=10, decimal_places=2),
        ),
        output_field=DecimalField(max_digits=10, decimal_places=2),
        db_persist=True,
    )

With this setup, every time a Product row is saved with a new price, the database automatically recalculates and stores discounted_price. Your application code never needs to compute it or remember to update it. You just read product.discounted_price and get the correct value.

Key Constraints to Know

There are some important rules that come with GeneratedField:

You cannot write to it. Attempting to set a value on a GeneratedField will raise an error. The database owns this field entirely.

The expression can only reference columns in the same row. You cannot reference other tables, subqueries, or non-deterministic functions like the current timestamp.

Migrations are required. Like any model field change, adding a GeneratedField requires creating and running a migration. The database column is created with the appropriate generated column definition.

Database support varies. PostgreSQL and MySQL have the broadest support. SQLite supports STORED but not VIRTUAL. Always check what your database version supports before using it.

When to Use It

GeneratedField is a good fit when a value is always derivable from other columns in the same row, when you find yourself writing signals or overriding save() just to keep a field in sync, or when you want to ensure consistency at the database level regardless of what application code does.

It is not a fit for computations that depend on related models, external data, or anything that changes independently of the row itself.

Django’s GeneratedField is one of those additions that quietly solves a common pain point. By letting the database handle derived values instead of relying on application-level logic, you get better consistency, less code to maintain, and the full performance benefits of database-native computed columns. If you are on Django 5.0 or later and find yourself manually syncing a field that is always derived from other fields, GeneratedField is worth reaching for.

Horilla HR Editorial Team Author

Horilla HR Editorial Team is a group of experienced HR professionals, HRIS consultants, and technical writers who are passionate about HR software. We have deep, hands-on understanding of the HR landscape — from hiring and onboarding to payroll compliance and workforce analytics — and are committed to providing our readers with the most up-to-date and accurate content. We have written extensively on a variety of HR software topics, including applicant tracking systems, performance management software, employee engagement tools, and payroll software. Our content is reviewed against real product capabilities and current compliance standards. We are always looking for new ways to share our knowledge with the HR community. If you have a question about HR software, please don't hesitate to contact us.