Django 迁移与多个数据库

Posted

技术标签:

【中文标题】Django 迁移与多个数据库【英文标题】:Django migrations with multiple databases 【发布时间】:2016-06-07 04:15:04 【问题描述】:

我很难创建数据迁移。我为我的应用程序使用了两个数据库。我在 settings.py 中配置了数据库,并在 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

以下是其中一款应用的模型和迁移:

# 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'),
    ]

问题是: 当我运行“迁移”命令时,仅迁移连接到默认数据库的应用程序。其余应用程序中的迁移永远不会运行。如果我使用 --database 选项为这样的应用程序启动迁移 - 它工作正常。

如何指定每次迁移的数据库?路由器不应该完全管理这个吗?还是我错过了什么?

【问题讨论】:

【参考方案1】:

您have to 为每个数据库运行一次migrate,并使用--database 指定目标。每次它都会咨询您的路由器以查看要在该数据库上实际执行哪些迁移。

我猜它是这样设计的,以支持明确而不是含蓄。例如,您的工作流程可能需要您在不同的时间迁移不同的数据库。

但请注意,您无法从输出中看出实际执行了哪些迁移,since:

如果allow_migrate() 返回False,则在db 上运行migrate 时,model_name 的任何迁移操作都将被静默跳过。

【讨论】:

谢谢,我已经结束了。 当 Django 提供DATABASE_ROUTERS 时,为什么不支持这个多数据库问题?这很奇怪。 迁移为两个数据库创建相同的身份验证结构。默认一侧是默认的 Django 表,另一侧是相同的默认 django 表,更多的是所选模板中的表。这是诀窍吗?

以上是关于Django 迁移与多个数据库的主要内容,如果未能解决你的问题,请参考以下文章

如果在 django 中使用多个数据库,如何仅迁移所需的模型表

django south 在多个数据库上

Django迁移错误地应用

django多数据库迁移:如何防止在每个数据库中创建django默认表

带有架构的 MSSQL 数据库的 Django 迁移错误

使用多个数据库的 Django 错误关系“auth_user”不存在