liveBook · Manning

Historical model state

As explained in Django in Action

A historical model state is the version of a model defined by the migrations up to a particular point in migration history.

A historical model state is the version of a Django model defined by migrations up to a particular point. Data migrations use it instead of the current model, because later changes may make today’s class incompatible with yesterday’s database shape. section 10.2

Use the historical state when a migration transforms existing rows:

  • Define the migration dependency so Django knows the exact earlier model state. section 10.2
  • Retrieve the version with apps.get_model("promoters", "Promoter") inside the migration function. section 10.2
  • Read and update rows through that version while moving the database state forward or backward. section 10.2

Copying promoter names

A data migration adds full_name and common_name, then obtains the historical Promoter model and copies first_name and last_name into the new fields. A reverse function restores the older fields. section 10.2

Listing 10.7 A migration script that calls Python to transform data during migration
# RiffMates/promoters/migrations/0004_data_fullname.py
from django.db import migrations

def de_westernize_names(apps, schema_editor):  #1
    # Can't import Promoter Model, the current version may be newer than
    # the one in this migration. Use historical version instead.
    Promoter = apps.get_model("promoters", "Promoter")  #2
    for promoter in Promoter.objects.all():  #3
        promoter.full_name = f"{promoter.first_name} {promoter.last_name}"
        promoter.common_name = promoter.first_name
        promoter.save()

def re_westernize_names(apps, schema_editor):  #4
    Promoter = apps.get_model("promoters", "Promoter")
    for promoter in Promoter.objects.all():
        promoter.first_name = promoter.common_name
        length = len(promoter.first_name)
        promoter.last_name = promoter.full_name[length + 1:]

    promoter.save()

class Migration(migrations.Migration):
    dependencies = [
        ("promoters", "0003_promoter_common_name_promoter_full_name"),
    ]

    operations = [
        migrations.RunPython(  #5
            de_westernize_names,
            re_westernize_names
        ),
    ]

Inspect the complete migration pattern, including historical lookup, row iteration, field translation, and reversal. section 10.2

How Django in Action covers it

How deep it goes
Explains historical lookup and reversible row updates, without detailing Django’s broader migration internals.
Examples
Demonstrates copying promoter first and last names into full and common name fields.
What it assumes
Assumes familiarity with Django models and migrations while demonstrating the historical lookup technique directly.
What you can do after
Builds reversible data migrations that operate against the model version matching their migration point.
How it connects
Connects Django migrations with RunPython, data migration, model state, and database schema changes.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Django in Action. The section links point to the parts of the book it draws on.