有没有办法指定 Django 迁移中 RunPython 操作所关注的数据库别名?
Is there a way to specify the database alias that is concerned by a RunPython operation in a Django migration?
我有一个使用两个数据库的 Django 项目。我定义了一个 Database Router
并且在 运行 迁移时一切正常,除了 RunPython
迁移操作:在这种情况下我必须 "manually" 检查 RunPython
代码是哪个数据库别名的代码函数 运行 决定是否应用给定的操作。
到目前为止,我已经实现了一个装饰器,我在每个 RunPython
代码函数上使用它来检查是否 运行 基于当前数据库别名的操作。它工作正常,但我想知道 Django 是否已经提供了一种方法来指定 RunPython
迁移所涉及的数据库别名,而无需自定义代码。有这样的方法吗?
有关信息,这是装饰器:
def run_for_db_aliases(database_aliases):
def decorator(migration_function):
def decorated(apps, schema_editor):
if schema_editor.connection.alias not in database_aliases:
return
return migration_function(apps, schema_editor)
return decorated
return decorator
这允许我为 RunPython
迁移定义代码,如下所示:
@run_for_db_aliases(['default'])
def forwards_func(apps, schema_editor):
# Perform data operations on models that are stored in the 'default' database
...
是否有更简洁的方法来执行此操作,例如实例化 RunPython
操作时的选项?
编辑:
这是我使用的模型和数据库路由器。
my_project/my_app/models.py
class A(models.Model):
# The table for this model is in the 'default' database
name = models.CharField(max_length=128)
class B(models.Model):
# The table for this model is in the 'other' database
description = models.CharField(max_length=128)
my_project/db_routers.py
class MyDBRouter(object):
def _is_in_other(self, model):
return model._meta.app_label == 'my_app' and model._meta.model_name == 'b'
def db_for_read(self, model, **hints):
return 'other' if self._is_in_other(model) else None
def db_for_write(self, model, **hints):
return 'other' if self._is_in_other(model) else None
def allow_relation(self, obj1, obj2, **hints):
# Pointless in this example
return None
def allow_migrate(self, db, model):
if db == 'other':
return self._is_in_other(model)
if self._is_in_other(model):
return False
return None
自 Django 1.8 以来已解决的问题:https://docs.djangoproject.com/en/1.10/releases/1.8/#migrations
The migration operations RunPython and RunSQL now call the allow_migrate() method of database routers. The router can use the newly introduced app_label and hints arguments to make a routing decision. To take advantage of this feature you need to update the router to the new allow_migrate signature
我有一个使用两个数据库的 Django 项目。我定义了一个 Database Router
并且在 运行 迁移时一切正常,除了 RunPython
迁移操作:在这种情况下我必须 "manually" 检查 RunPython
代码是哪个数据库别名的代码函数 运行 决定是否应用给定的操作。
到目前为止,我已经实现了一个装饰器,我在每个 RunPython
代码函数上使用它来检查是否 运行 基于当前数据库别名的操作。它工作正常,但我想知道 Django 是否已经提供了一种方法来指定 RunPython
迁移所涉及的数据库别名,而无需自定义代码。有这样的方法吗?
有关信息,这是装饰器:
def run_for_db_aliases(database_aliases):
def decorator(migration_function):
def decorated(apps, schema_editor):
if schema_editor.connection.alias not in database_aliases:
return
return migration_function(apps, schema_editor)
return decorated
return decorator
这允许我为 RunPython
迁移定义代码,如下所示:
@run_for_db_aliases(['default'])
def forwards_func(apps, schema_editor):
# Perform data operations on models that are stored in the 'default' database
...
是否有更简洁的方法来执行此操作,例如实例化 RunPython
操作时的选项?
编辑:
这是我使用的模型和数据库路由器。
my_project/my_app/models.py
class A(models.Model):
# The table for this model is in the 'default' database
name = models.CharField(max_length=128)
class B(models.Model):
# The table for this model is in the 'other' database
description = models.CharField(max_length=128)
my_project/db_routers.py
class MyDBRouter(object):
def _is_in_other(self, model):
return model._meta.app_label == 'my_app' and model._meta.model_name == 'b'
def db_for_read(self, model, **hints):
return 'other' if self._is_in_other(model) else None
def db_for_write(self, model, **hints):
return 'other' if self._is_in_other(model) else None
def allow_relation(self, obj1, obj2, **hints):
# Pointless in this example
return None
def allow_migrate(self, db, model):
if db == 'other':
return self._is_in_other(model)
if self._is_in_other(model):
return False
return None
自 Django 1.8 以来已解决的问题:https://docs.djangoproject.com/en/1.10/releases/1.8/#migrations
The migration operations RunPython and RunSQL now call the allow_migrate() method of database routers. The router can use the newly introduced app_label and hints arguments to make a routing decision. To take advantage of this feature you need to update the router to the new allow_migrate signature