Django Migrations: Your Database’s Time Machine 🚀
The Story of Migrations
Imagine you have a LEGO house. You built it yesterday. Today, you want to add a new room. But wait! You can’t just smash everything and rebuild. You need a plan — a step-by-step guide that says:
“Add 10 blue bricks here. Remove 2 red bricks there.”
Django Migrations are exactly that plan — but for your database!
Every time you change your models (the blueprint of your data), Django creates a migration file. This file tells the database exactly what changed and how to update itself — without losing any data.
🎯 Migrations Overview
What Are Migrations?
Think of migrations like diary entries for your database.
| Day | What Happened |
|---|---|
| Day 1 | Created a User table |
| Day 2 | Added email field to User |
| Day 3 | Removed nickname field |
Each entry (migration) remembers exactly what changed. If you ever need to go back in time, you can!
Why Do We Need Them?
Without migrations, you’d have to:
- Manually write SQL commands
- Hope you remember every change
- Pray nothing breaks
With migrations:
- Django tracks changes automatically
- Changes are version-controlled
- Your whole team stays in sync
graph TD A["You Change models.py"] --> B["Run makemigrations"] B --> C["Migration File Created"] C --> D["Run migrate"] D --> E["Database Updated!"]
The Migration Workflow
- Change your model (add/remove/modify fields)
- Create a migration with
makemigrations - Apply it with
migrate
That’s it! Three simple steps.
🛠️ Migration Commands
Django gives you powerful commands. Let’s meet them!
1. makemigrations — The Detective
This command detects what changed in your models.
# You added this field to your model:
class Book(models.Model):
title = models.CharField(max_length=200)
pages = models.IntegerField() # NEW!
Now run:
python manage.py makemigrations
Django says: “Aha! I see you added pages. Let me write that down!”
Output:
Migrations for 'library':
0002_book_pages.py
- Add field pages to book
2. migrate — The Builder
This command applies migrations to your database.
python manage.py migrate
Django now actually creates the new column in your database table.
3. showmigrations — The Historian
Want to see all migrations? This shows them!
python manage.py showmigrations
Output:
library
[X] 0001_initial
[X] 0002_book_pages
[ ] 0003_book_author
[X]= Applied (done!)[ ]= Not applied yet
4. sqlmigrate — The Translator
Want to see the actual SQL code? Peek inside!
python manage.py sqlmigrate library 0002
Output:
ALTER TABLE "library_book"
ADD COLUMN "pages" integer NOT NULL;
5. migrate --fake — The Pretender
Sometimes you need Django to mark a migration as done without actually running it.
python manage.py migrate library 0002 --fake
Use with caution! It’s like saying “Trust me, the database already has this.”
Command Quick Reference
| Command | What It Does |
|---|---|
makemigrations |
Creates migration files |
migrate |
Applies migrations |
showmigrations |
Lists all migrations |
sqlmigrate app 000X |
Shows SQL for a migration |
migrate --fake |
Marks as done (no action) |
migrate app zero |
Undoes ALL app migrations |
📁 Migration Files and Operations
What’s Inside a Migration File?
Every migration file lives in yourapp/migrations/ folder.
Let’s peek inside 0002_book_pages.py:
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('library', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='book',
name='pages',
field=models.IntegerField(),
),
]
Breaking It Down
1. dependencies — What must run first
dependencies = [
('library', '0001_initial'),
]
This migration waits for 0001 to finish first.
2. operations — The actual changes
operations = [
migrations.AddField(...),
]
This is the list of database operations.
Common Operations
graph TD A["Migration Operations"] --> B["CreateModel"] A --> C["DeleteModel"] A --> D["AddField"] A --> E["RemoveField"] A --> F["AlterField"] A --> G["RenameField"] A --> H["RenameModel"]
| Operation | What It Does |
|---|---|
CreateModel |
Makes a new table |
DeleteModel |
Removes a table |
AddField |
Adds a column |
RemoveField |
Removes a column |
AlterField |
Changes a column |
RenameField |
Renames a column |
RenameModel |
Renames a table |
Example: Adding a Field
migrations.AddField(
model_name='book',
name='author',
field=models.CharField(
max_length=100,
default='Unknown'
),
)
Example: Removing a Field
migrations.RemoveField(
model_name='book',
name='old_field',
)
Example: Renaming a Field
migrations.RenameField(
model_name='book',
old_name='title',
new_name='book_title',
)
🔄 Data Migrations
Sometimes you need to move data around, not just change structure. That’s where data migrations shine!
What Are Data Migrations?
Imagine you split a fullname field into first_name and last_name.
Structure migrations create the new fields. Data migrations move the names over!
Creating a Data Migration
python manage.py makemigrations --empty library
This creates a blank migration file for you to fill in.
The RunPython Operation
from django.db import migrations
def split_names(apps, schema_editor):
User = apps.get_model('library', 'User')
for user in User.objects.all():
parts = user.fullname.split(' ')
user.first_name = parts[0]
user.last_name = parts[-1]
user.save()
def reverse_names(apps, schema_editor):
User = apps.get_model('library', 'User')
for user in User.objects.all():
user.fullname = f"{user.first_name} {user.last_name}"
user.save()
class Migration(migrations.Migration):
dependencies = [
('library', '0003_add_name_fields'),
]
operations = [
migrations.RunPython(
split_names,
reverse_names
),
]
Key Points About Data Migrations
1. Always use apps.get_model()
# CORRECT - gets the model at migration time
User = apps.get_model('library', 'User')
# WRONG - might have different fields now
from library.models import User
2. Write a reverse function
migrations.RunPython(forward, reverse)
If something goes wrong, Django can undo it!
3. Keep them small Data migrations can be slow. Process in batches if needed.
When to Use Data Migrations
| Scenario | Use Data Migration? |
|---|---|
| Split one field into two | ✅ Yes |
| Combine two fields into one | ✅ Yes |
| Set default values based on logic | ✅ Yes |
| Just add a new field | ❌ No |
| Just rename a field | ❌ No |
🎬 Real-World Example
Let’s walk through a complete scenario!
Step 1: Create Initial Model
# models.py
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
python manage.py makemigrations
python manage.py migrate
Step 2: Add a New Field
# models.py (updated)
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published = models.BooleanField(default=False)
python manage.py makemigrations
python manage.py migrate
Step 3: Data Migration
Now set all existing articles as published:
python manage.py makemigrations --empty blog
# 0003_set_published.py
from django.db import migrations
def set_all_published(apps, schema_editor):
Article = apps.get_model('blog', 'Article')
Article.objects.all().update(published=True)
class Migration(migrations.Migration):
dependencies = [
('blog', '0002_article_published'),
]
operations = [
migrations.RunPython(set_all_published),
]
python manage.py migrate
Done! All articles are now published.
💡 Pro Tips
Tip 1: Check Before You Migrate
python manage.py showmigrations
python manage.py sqlmigrate app 0002
Tip 2: Squash Old Migrations
Too many migration files? Combine them!
python manage.py squashmigrations app 0001 0005
Tip 3: Never Edit Applied Migrations
If a migration is already in production, create a new one instead!
Tip 4: Test Migrations Locally First
Always run migrate on a test database before production.
🏁 Summary
graph TD A["Change models.py"] --> B["makemigrations"] B --> C["Migration File Created"] C --> D["migrate"] D --> E["Database Updated"] F["Need Data Changes?"] --> G["makemigrations --empty"] G --> H["Add RunPython"] H --> D
| Concept | Remember |
|---|---|
| Migrations | Diary entries for your database |
| makemigrations | Detects changes, creates files |
| migrate | Applies changes to database |
| Migration Files | Python files with operations |
| Data Migrations | Move/transform actual data |
You Did It! 🎉
You now understand Django migrations like a pro!
Remember:
- Change your models
- Create migrations with
makemigrations - Apply them with
migrate - Use data migrations when you need to move data
Your database is no longer scary. It’s your time machine, and you control it!
Happy coding! 🚀
