How to Create Custom Migration in Django: Step-by-Step Guide
To create a custom migration in Django, generate a migration file using
python manage.py makemigrations and then edit it to add a RunPython operation with your custom Python function. This lets you run specific code during migration, such as data transformations or complex schema changes.Syntax
A custom migration in Django uses the RunPython operation inside a migration file. You define two functions: one for applying the migration and one for reversing it. These functions receive apps and schema_editor as parameters to access models and the database.
RunPython(forwards_func, backwards_func): Runs Python code during migration.forwards_func(apps, schema_editor): Code to apply changes.backwards_func(apps, schema_editor): Code to undo changes.
python
from django.db import migrations def forwards_func(apps, schema_editor): # Your code here pass def backwards_func(apps, schema_editor): # Undo code here pass class Migration(migrations.Migration): dependencies = [ # ('app_name', 'previous_migration'), ] operations = [ migrations.RunPython(forwards_func, backwards_func), ]
Example
This example shows a custom migration that sets a default value for a new field is_active in a model UserProfile. The forwards_func sets is_active to True for all existing records. The backwards_func resets it to False.
python
from django.db import migrations def forwards_func(apps, schema_editor): UserProfile = apps.get_model('myapp', 'UserProfile') for user in UserProfile.objects.all(): user.is_active = True user.save() def backwards_func(apps, schema_editor): UserProfile = apps.get_model('myapp', 'UserProfile') for user in UserProfile.objects.all(): user.is_active = False user.save() class Migration(migrations.Migration): dependencies = [ ('myapp', '0001_initial'), ] operations = [ migrations.RunPython(forwards_func, backwards_func), ]
Output
When applied, all UserProfile records will have is_active set to True; when reversed, set to False.
Common Pitfalls
- Not defining a reverse function can make rollback impossible; always provide a
backwards_funcor usemigrations.RunPython.noop. - Accessing models directly from imports instead of using
apps.get_modelcan cause errors because migrations use historical models. - Performing heavy database operations inside migrations can slow down deployment; keep logic simple.
python
from django.db import migrations # Wrong: importing model directly #from myapp.models import UserProfile def forwards_func(apps, schema_editor): UserProfile = apps.get_model('myapp', 'UserProfile') # Correct way # ... your code ... class Migration(migrations.Migration): dependencies = [ ('myapp', '0001_initial'), ] operations = [ migrations.RunPython(forwards_func), # No reverse function - risky ]
Quick Reference
Remember these key points when creating custom migrations:
- Use
RunPythonto run Python code during migrations. - Always use
apps.get_modelto access models inside migration functions. - Provide both forward and backward functions for safe rollbacks.
- Keep migration code simple and fast.
Key Takeaways
Use migrations.RunPython with forward and backward functions to create custom migrations.
Access models inside migrations with apps.get_model, not direct imports.
Always provide a reverse function to allow safe rollback of migrations.
Keep migration logic simple to avoid slow deployments.
Test custom migrations in a development environment before applying to production.