web-dev-qa-db-fra.com

Django migrations avec plusieurs bases de données

J'ai du mal à créer des migrations de données. J'utilise deux bases de données pour mes applications. J'ai configuré des bases de données dans settings.py et j'ai également créé un routeur comme dans 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

Voici le modèle et les migrations de l'une de ces 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'}),
    ]

Le problème est: lorsque j'exécute la commande "migrate", seules les applications connectées à la base de données par défaut sont migrées. Les migrations dans le reste des applications ne sont jamais exécutées. Si je lance la migration pour une telle application avec l'option --database - cela fonctionne très bien.

Comment puis-je spécifier la base de données par migration? Le routeur n'est-il pas censé gérer exactement cela? Ou j'ai raté autre chose?

18
Leon Kladnitsky

Vous devez exécuter migrate une fois pour chaque base de données, en spécifiant la cible avec --database. Chaque fois, il consultera votre routeur pour voir quelles migrations effectuer réellement sur cette base de données.

Je suppose qu'il a été conçu de cette façon pour favoriser l'explicitation au lieu de l'implicence. Par exemple, votre flux de travail peut vous obliger à migrer les différentes bases de données à différents moments.

Notez, cependant, que vous ne pourrez pas dire à partir de la sortie quelles migrations ont été réellement effectuées, puisque :

Si allow_migrate() renvoie False, toutes les opérations de migration pour model_name Seront ignorées en silence lors de l'exécution de migrate sur db.

19