Django 5.0 brings a powerful new feature to the table: GeneratedField. This addition allows developers to define fields with values created directly by the database, rather than Django itself.
This represents a shift in how we can handle computed columns, default values from database functions, and auto-updating timestamps.

What is GeneratedField?

GeneratedField is a new class in Django 5.0 that allows for the creation of fields that are always computed based on other fields in the model. The key characteristic of GeneratedField is that it’s managed and updated by the database itself, using the GENERATED ALWAYS SQL syntax.

Types of generated columns

There are two primary types of generated columns:

  1. Stored: Computed when written (inserted or updated) and occupies storage like a regular column.
  2. Virtual: Occupies no storage and is computed when read.

To put this in perspective:

  • A virtual generated column is similar to a database view
  • A stored generated column is analogous to a materialized view

Key components of GeneratedField

Let’s break down the main components of the GeneratedField class:


# More info: https://docs.djangoproject.com/en/5.0/ref/models/fields/#generatedfield
class GeneratedField(expression, output_field, db_persist=None, **kwargs)

1. expression

This is an Expression used by the database to automatically set the field value each time the model is changed. It’s crucial to note that:

  • Expressions should be deterministic
  • They should only reference fields within the same model (database table)
  • Generated fields cannot reference other generated fields
  • Database backends may impose additional restrictions

2. output_field

This is a model field instance that defines the field’s data type.

3. db_persist

This boolean parameter determines if the database column should occupy storage as if it were a real column:

  • If False, the column acts as a virtual column and doesn’t occupy database storage space
  • If True, it behaves like a stored column

It’s important to note that database support varies:

  • PostgreSQL only supports persisted columns
  • Oracle only supports virtual columns

Practical example

Let’s look at a practical example of how to use GeneratedField in a Django model:


from django.db import models
from django.db.models import GeneratedField

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

In this example:

  • We define a Product model with name and price fields
  • The discounted_price is a GeneratedField that automatically calculates a 10% discount
  • The expression models.F('price') * 0.9 computes the discounted price
  • We specify the output field as a DecimalField to match the price field’s type
  • db_persist=True indicates this will be a stored generated column

Django book

Benefits of using GeneratedField

  1. Improved performance: Calculations are done at the database level, reducing the load on the application server.
  2. Data consistency: Ensures all applications and queries see the same generated values.
  3. Reduced code duplication: No need to replicate database logic in Django models or views.
  4. Automatic updates: The database handles updates to the generated field, eliminating the need for manual intervention.

Important considerations

Refreshing data

Since the database computes the value, the object must be reloaded to access the new value after save(). You can use the refresh_from_db() method to achieve this.

Database limitations

It’s crucial to be aware of database-specific restrictions on generated fields. Django doesn’t validate these restrictions, so the database may raise errors. For example, PostgreSQL requires functions and operators referenced in a generated column to be marked as IMMUTABLE.

Always check that your expression is supported on your specific database. Consult the documentation for your database system (MariaDB, MySQL, Oracle, PostgreSQL, or SQLite) for detailed information on their support and limitations for generated columns.

Use cases for GeneratedField

  1. Computed columns: Like our discounted price example above.
  2. Default values from database functions: You can use database-specific functions to generate default values.
  3. Auto-updating timestamps: Create fields that automatically update with the current timestamp on each modification.

Conclusion

GeneratedField is a powerful addition to Django’s ORM toolkit. It bridges the gap between application-level and database-level computations, offering developers more flexibility and efficiency in handling derived data.

By leveraging the power of database-generated fields, Django applications can benefit from improved performance, enhanced data consistency, and reduced code complexity. As with any new feature, it’s important to understand its capabilities and limitations, especially concerning database-specific implementations.

As Django continues to evolve, features like GeneratedField demonstrate the framework’s commitment to providing developers with powerful tools that leverage the full capabilities of modern database systems.

For more detailed information and the latest updates, be sure to check the official Django documentation at https://docs.djangoproject.com/en/5.0/ref/models/fields/#generatedfield.

Categorized in:

MLOps, Models deployment, Programming,

Last Update: 14/09/2024