Django Migrations with Multiple Databases

It's hard for me to create data migration. I use two databases for my applications. I set up the databases in settings.py and also created a router, as in Django docs .

# settings.py DB_HOST = 'localhost' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'helios', 'HOST': DB_HOST, 'OPTIONS': { 'read_default_file': join(dirname(__file__), 'default.cnf'), }, }, 'other': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'gala_pol', 'HOST': DB_HOST, 'OPTIONS': { 'read_default_file': join(dirname(__file__), 'other.cnf'), }, }, DATABASE_APPS_MAPPING = { 'contenttypes': 'default', 'auth': 'default', 'admin': 'default', 'sessions': 'default', 'messages': 'default', 'staticfiles': 'default', 'woodsmen': 'default', 'helios': 'default', 'hush': 'default', 'hunt': 'other', 'meat': 'other', 'beast': 'other', } # routers.py class DatabaseAppsRouter(object): def db_for_read(self, model, **hints): if model._meta.app_label in settings.DATABASE_APPS_MAPPING: return settings.DATABASE_APPS_MAPPING[model._meta.app_label] return None def db_for_write(self, model, **hints): if model._meta.app_label in settings. return settings.DATABASE_APPS_MAPPING[model._meta.app_label] return None def allow_relation(self, obj1, obj2, **hints): db1 = settings.DATABASE_APPS_MAPPING.get(obj1._meta.app_label) db2 = settings.DATABASE_APPS_MAPPING.get(obj2._meta.app_label) if db1 and db2: return db1 == db2 return None def allow_migrate(self, db, app_label, model_name=None, **hints): if db in settings.DATABASE_APPS_MAPPING.values(): return settings.DATABASE_APPS_MAPPING.get(app_label) == db elif app_label in settings.DATABASE_APPS_MAPPING: return False 

Here is the model and migration of one of these applications:

 # hunt.models.py class Dish(models.Model): """ Investigation case """ display_name = models.CharField(max_length=64, unique=True) department = models.ForeignKey(Kitchen, null=True) case_type = models.PositiveSmallIntegerField(choices=CASE_TYPE_CHOICES, default=DEF_CASE_TYPE) created_at = models.DateTimeField(blank=True, null=True) comment = models.CharField(max_length=256, blank=True, null=True) class Meta: verbose_name = 'case' app_label = 'hunt' def __unicode__(self): return (u'%s (%s)' % (self.display_name, self.created_at)).strip() # hunt.migrations.0001_initial.py class Migration(migrations.Migration): app_label = 'hunt' dependencies = [ ] operations = [ migrations.CreateModel( name='Dish', fields=[ ('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), ('display_name', models.CharField(max_length=64, unique=True)), ('case_type', models.PositiveSmallIntegerField(default=0, choices=[(0, 'Unknown'), (1, 'General'), (2, 'Terror'), (3, 'Narco'), (4, 'Fraud'), (5, 'Slavery'), (6, 'Traffic'), (7, 'RICO'), (8, 'War'), (9, 'Cyber'), (20, 'Other')])), ('created_at', models.DateTimeField(null=True, blank=True)), ('comment', models.CharField(max_length=256, null=True, blank=True)), ], options={ 'verbose_name': 'case', }, ), ] # hunt.migrations.0002_add_hunts.py def create_initial_hunts(apps, schema_editor): if settings.DEBUG: print('\nContent added') class Migration(migrations.Migration): dependencies = [ ('hunt', '0001_initial'), ] operations = [ migrations.RunPython(create_initial_hunts, hints={'schema_editor': 'other'}), ] 

The problem is this: When I run the "migrate" command, only applications connected to the database by default are migrated. Migrations in other applications never start. If I start a migration for such an application with the --database option - it works fine.

How can I specify a database for each migration? Shouldn't a router handle just that? Or am I missing something else?

+13
django
source share
1 answer

You must run migrate once for each database, specifying the target with --database . Each time, he will consult with your router to see what migrations actually perform in this database.

I assume that it was designed to promote explicit versus implicit. For example, for your workflow, you might need to migrate different databases at different times.

However, note that based on the output, you will not be able to determine which migrations have actually been performed since :

If allow_migrate() returns False , any migration operations for model_name will be automatically skipped when running migrate on db .

+14
source share

All Articles