• ↑↓ pour naviguer
  • pour ouvrir
  • pour sélectionner
  • ⌘ ⌥ ↵ pour ouvrir dans un panneau
  • ←→ pour naviguer
  • esc pour rejeter
⌘ '
raccourcis clavier

Formal Definition

Database Migrations are Django’s version-control system for database schema, represented as Python files containing Operations (CreateModel, AddField, AlterField, RunSQL, RunPython) that transform the database from one state to another, tracked in the django_migrations table to ensure idempotent application across environments.

Explanation

Migrations solve the problem of evolving database schema alongside code without manual SQL scripts or data loss. When models change, makemigrations generates a new migration file by comparing current models to the historical state reconstructed from previous migrations. migrate applies unapplied migrations in dependency order, recording each in django_migrations. This enables team collaboration, CI/CD integration, and safe rollbacks (when operations are reversible).

How It Works

  1. Models changed — Developer modifies models.py (add field, change type, new model)
  2. Autodetector runsmakemigrations compares current models to project state from last migration
  3. Operations generated — Creates Migration class with operations = [AddField(...), ...]
  4. Dependencies resolved — Migration declares dependencies = [('app', '0001_initial'), ...]
  5. Migration appliedmigrate runs operations in topological order, updates django_migrations
  6. State reconstructed — Future makemigrations replays all migrations to compute current state

Visual Explanation

database_migrations ModelsPy models.py class Book:    title = CharField()    # NEW: author = FK Makemigrations makemigrations Autodetector ModelsPy->Makemigrations 1. Change detected MigrationFile 0002_book_author.py operations = [  AddField(...) ] Makemigrations->MigrationFile 2. Generate ops Migrate migrate Executor MigrationFile->Migrate 3. Plan & apply DBTable django_migrations (app, name, applied) Migrate->DBTable 4. Record applied Database PostgreSQL ALTER TABLE book ADD COLUMN author_id... Migrate->Database 5. Execute SQL

Semantic Network

semantic_database_migrations THIS Database Migrations PRE1 Models / ORM THIS--PRE1 built from PRE2 Historical Model State THIS--PRE2 built from PRE3 Dependency Graph THIS--PRE3 built from OUT1 Schema Operations THIS--OUT1 builds into OUT2 Data Migrations THIS--OUT2 builds into OUT3 Squash Migrations THIS--OUT3 builds into OUT4 Fake Migrations THIS--OUT4 builds into CON1 Alembic (SQLAlchemy) THIS--CON1 contrasts with CON2 Flyway (SQL-based) THIS--CON2 contrasts with REL1 Transaction Wrapper THIS--REL1 related REL2 RunPython (Custom Logic) THIS--REL2 related

Key Properties

  • Declarative operations: CreateModel, AddField, AlterField, RemoveField, RunSQL, RunPython
  • Dependency graph: Linear per-app, cross-app via dependencies; topological sort ensures order
  • Reversibility: Most operations auto-reversible; RunPython needs reverse_code; RunSQL needs reverse SQL
  • Squashing: squashmigrations combines many migrations into one for faster initial setup
  • Historical models: apps.get_model('app', 'Model') in RunPython uses frozen model state

Connections

  • Built from: ORM — Source of schema changes
  • Built from: Historical Model State — Baseline for autodetection
  • Builds into: Schema Operations — Individual migration steps
  • Builds into: Data MigrationsRunPython for data transformation
  • Builds into: Squash Migrations — Optimize migration history
  • Contrasts with: Alembic — SQLAlchemy’s migration tool, similar but separate ecosystem
  • Contrasts with: Flyway — SQL-file based, not ORM-coupled
  • Related: Transaction Wrapper — Each migration in transaction (except PostgreSQL DDL)
  • Related: RunPython — Custom data migration logic

Edge Cases & Gotchas

  • Non-reversible migrations: RunPython without reverse_code blocks rollback; migrate --fake risky
  • Concurrent migrations: Two developers create 0003_... — resolve with makemigrations --merge
  • Large table ALTER: Adding column with default locks table; use AddFieldRunSQL (no default) → AlterField
  • Historical model drift: RunPython using current model instead of apps.get_model() breaks future migrations
  • Swap app models: swappable = 'AUTH_USER_MODEL' requires special handling in migrations