Django migrations with multiple databases

谁说我不能喝 提交于 2019-12-03 08:58:23

问题


I have a hard time with creating data migrations. I use two databases for my apps. I configured databases in settings.py and also created a router like 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 migrations of one of those apps:

# 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: When i run "migrate" command, only applications that connected to default database are migrated. The migrations in rest of the apps are never run. If I launch migrate for such an app with --database option - it works fine.

How can I specify the database per migration? Isn't the router supposed to manage exactly this? Or I missed something else?


回答1:


You have to run migrate once for each database, specifying the target with --database. Each time it will consult your router to see which migrations to actually perform on that database.

I'm guessing it was designed this way to favor explicitness over implicitness. For example, your workflow might require you to migrate the different databases at different times.

Note, though, that you won't be able to tell from the output which migrations were actually performed, since:

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



来源:https://stackoverflow.com/questions/35609509/django-migrations-with-multiple-databases

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!