I have a Django project that uses two databases. I defined a Database Router
and everything works fine when running migrations, except for RunPython
migration operations : in this case I have to "manually" check in the RunPython
code function on which database alias the code is run to decide whether or not to apply the given operations.
So far I have implemented a decorator that I use on every RunPython
code function that checks whether or not to run the operation based on the current database alias. It works fine, but I was wondering if Django already provided a way to specify the database alias(es) concerned by a RunPython
migration without having custom code. Is there such a way ?
For information, here is the decorator :
def run_for_db_aliases(database_aliases):
def decorator(migration_function):
def decorated(apps, schema_editor):
if schema_editor.connection.alias not in database_aliases:
return
return migration_function(apps, schema_editor)
return decorated
return decorator
This allows me to define code for RunPython
migrations like this :
@run_for_db_aliases(['default'])
def forwards_func(apps, schema_editor):
# Perform data operations on models that are stored in the 'default' database
...
Is there a cleaner way to do this, like an option when instantiating a RunPython
operation ?
EDIT:
Here is the models and database router I use.
my_project/my_app/models.py
class A(models.Model):
# The table for this model is in the 'default' database
name = models.CharField(max_length=128)
class B(models.Model):
# The table for this model is in the 'other' database
description = models.CharField(max_length=128)
my_project/db_routers.py
class MyDBRouter(object):
def _is_in_other(self, model):
return model._meta.app_label == 'my_app' and model._meta.model_name == 'b'
def db_for_read(self, model, **hints):
return 'other' if self._is_in_other(model) else None
def db_for_write(self, model, **hints):
return 'other' if self._is_in_other(model) else None
def allow_relation(self, obj1, obj2, **hints):
# Pointless in this example
return None
def allow_migrate(self, db, model):
if db == 'other':
return self._is_in_other(model)
if self._is_in_other(model):
return False
return None
Problem solved since Django 1.8 : https://docs.djangoproject.com/en/1.10/releases/1.8/#migrations