Django 防止远程数据库迁移

Django prevent migrations on remote database

我有一个连接到两个数据库的 Django 应用程序。我的一个数据库在不同的(生产)服务器上。我想非常确保在开发我的应用程序时,我不会不小心在生产服务器上迁移模型。我的理解是这样的:假设我的 settings.py 数据库是这样的:

DATABASES = {
    'default': {},
    'remote_db': {
        'NAME'    : 'important_remote_db_name',
        'ENGINE'  : 'django.db.backends.mysql',
        'USER'    : 'someuser',
        'PASSWORD': 'somepass',
        'HOST'    : 'some.production.host.com',
        'PORT'    : '3306',
    },
    'myapp_db': {
        'NAME'    : 'my_app_db_name',
        'ENGINE'  : 'django.db.backends.mysql',
        'USER'    : 'localuser',
        'PASSWORD': 'localpassword'
    }
}

现在假设我还有一个名为 RemoteDBRouter 的路由器 class。像所有路由器一样,class 将有一个方法 allow_migrate。请注意,远程数据库使用 Django 身份验证模型,因此用户模型将具有 app_label 'auth',远程数据库也有自己的模型 app_label 'remoteapp'。有了这些信息,我看到了 allow_migrate 方法的两种可能性:

#OPTION 1
def allow_migrate(self, db, app_label, model_name=None, **hints):
    if app_label == 'auth' or app_label == 'remoteapp':
        return db == 'remote_db'
    return None

#OPTION 2
def allow_migrate(self, db, app_label, model_name=None, **hints):
    if app_label == 'auth' or app_label == 'remoteapp':
        return False
    return None

我应该使用哪一个?选项 2 更简单,因为它只是说我不应该迁移 app_label 表示模型来自远程数据库的任何模型。选项 1 会额外检查 db 字段是否为 'remote_db'(我假设我们需要检查 'remote_db' 而不是 'remote_db_name')。我用哪一个重要吗?我担心如果我使用选项 1 并且数据库检查失败,该方法将 return None 然后 Django 代码将检查下一个路由器 class 其中 allow_migrate可能 return 正确。

您希望 RemoteDBRouterremote_db 数据库具有权威性。您不想控制它从本地计算机迁移到 authremoteapp 或其他应用程序。其他数据库不一定由 RemoteDBRouter 控制。因此你开始:

    if db == 'remote_db':
        return False

问题是,当您开发写操作时,您是否希望有时将 authremoteapp 切换到本地,或者您是否希望只有只读访问权限,并且永远不需要在本地创建这些表.然后你可以添加:

    if app_label == 'auth' or app_label == 'remoteapp':
        return False

其他数据库的迁移可以由默认路由器或其他路由器控制:

    return None

在本地创建一个测试数据库测试比较复杂。

DATABASES = {
    'remote_db': {
        ...
        'HOST': 'some.production.host.com',
        'USER': 'some_readonly_user',   # read-only for security
        'TEST': {
            'HOST': 'localhost',
            ...
        }
    }
}

您也可以选择通过路由器规则支持对远程数据库的只读访问:

def db_for_write(model, **hints):
    if model._meta.app_label in ('auth', 'remoteapp'):
        return 'myapp_db'  # or maybe the db 'default' where the model doesn't exist

如果你写错了,一个异常总比损害生产数据好。路由器可以通过多种方式覆盖,例如通过 using=db 参数或 .using(db) 方法。为了安全起见,连接应该由只读用户进行。