【问题标题】:Django Database RoutingDjango 数据库路由
【发布时间】:2021-05-13 06:35:41
【问题描述】:

我在 Settings.py 中定义了 3 个数据库,并在各自的应用程序文件夹中为两个应用程序定义了路由器。当我尝试分别为应用程序运行manage.py migrate --database="app_db" 时,它只运行default 和第二个数据库列表项。如果我更改数据库列表的顺序,它将不会执行最后一个,而只会执行第二个。

Settings.py

INSTALLED_APPS = [
    # django apps
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    # my apps
    "cred",
    "dms",
    # third party apps
    "rest_framework",
]


DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "databases/db.sqlite3",
    },
    "dms_db": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "databases/dms.sqlite3",
    },
    "cred_db": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "databases/cred.sqlite3",
    },
}

DATABASE_ROUTERS = [
    "dms.routers.DMSRouter",
    "cred.routers.CredRouter",
]

AUTH_USER_MODEL = "cred.User"
CRED_DB_ROUTER = "cred_db"
DMS_DB_ROUTER = "dms_db"

如果我将 dms_db 放在列表索引 1 处,那么它将迁移但 cred_db 不会。如果我将 cred_db 放在索引 1 处,那么它将迁移但 dms_db 不会。

Cred.Router.py

from django.conf import settings


class CredRouter:
    route_app_labels = ["auth", "cred", "contenttypes"]

    def db_for_read(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return settings.CRED_DB_ROUTER
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:
            return settings.CRED_DB_ROUTER
        return None

    def allow_relation(self, obj1, obj2, **hints):
        if (
            obj1._meta.app_label in self.route_app_labels
            or obj2._meta.app_label in self.route_app_labels
        ):
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if app_label in self.route_app_labels:
            return db == settings.CRED_DB_ROUTER
        return False

dms.router.py

from django.conf import settings


class DMSRouter:
    route_app_labels = [
        "dms",
    ]

    def db_for_read(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:  # noqa
            return settings.DMS_DB_ROUTER
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label in self.route_app_labels:  # noqa
            return settings.DMS_DB_ROUTER
        return None

    def allow_relation(self, obj1, obj2, **hints):
        if (
            obj1._meta.app_label in self.route_app_labels  # noqa
            or obj2._meta.app_label in self.route_app_labels  # noqa
        ):
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if app_label in self.route_app_labels:
            return db == settings.DMS_DB_ROUTER
        return False

我在做什么

迁移文件夹中只有 initial_0001.py。所以我猜?它没有引起任何问题。不确定。

manage.py makemigrations 
manage.py migrate
manage.py migrate --database="cred_db"
manage.py migrate --database="dms_db"

所有模型都完全共享这种结构。

class Organization(models.Model):
    name = models.CharField(max_length=255)
    email = models.EmailField()
    codename = models.CharField(max_length=254, unique=True)
    ... 

    objects = models.Manager()

    class Meta:
        verbose_name = _("organization")
        verbose_name_plural = _("organization")

随着项目的发展,我们将拥有更多的数据库连接,因为我们将集成现有的 Django 应用程序,并且每个应用程序都已经建立了专用的数据库服务器。所以这个项目将连接到至少 8-10 个不同的数据库。通过移动手动迁移每个将是他们中的许多人的问题。

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    路由器适用于所有数据库,因此DMSRouter 中的allow_migrate dms_dbcred_db 调用。由于DMSRouter 仅允许将表迁移到dms 应用程序,因此您的其他应用程序表永远不会迁移。您需要做的是使用在allow_migrate 方法中传递的参数db,如果它不是路由器正在处理的参数,则使用return None 而不是False

    Cred.Router.py

    class CredRouter:
        route_app_labels = ["auth", "cred", "contenttypes"]
    
        def db_for_read(self, model, **hints):
            if model._meta.app_label in self.route_app_labels:
                return settings.CRED_DB_ROUTER
            return None
    
        def db_for_write(self, model, **hints):
            if model._meta.app_label in self.route_app_labels:
                return settings.CRED_DB_ROUTER
            return None
    
        def allow_relation(self, obj1, obj2, **hints):
            if (
                obj1._meta.app_label in self.route_app_labels
                or obj2._meta.app_label in self.route_app_labels
            ):
                return True
            return None
    
        def allow_migrate(self, db, app_label, model_name=None, **hints):
            if app_label in self.route_app_labels:
                return db == settings.CRED_DB_ROUTER
            else if db == settings.CRED_DB_ROUTER:
                return False # Only apps in `route_app_labels` will be migrated to `cred_db`
            return None # Let other routers decide
    

    dms.router.py

    from django.conf import settings
    
    
    class DMSRouter:
        route_app_labels = [
            "dms",
        ]
    
        def db_for_read(self, model, **hints):
            if model._meta.app_label in self.route_app_labels:  # noqa
                return settings.DMS_DB_ROUTER
            return None
    
        def db_for_write(self, model, **hints):
            if model._meta.app_label in self.route_app_labels:  # noqa
                return settings.DMS_DB_ROUTER
            return None
    
        def allow_relation(self, obj1, obj2, **hints):
            if (
                obj1._meta.app_label in self.route_app_labels  # noqa
                or obj2._meta.app_label in self.route_app_labels  # noqa
            ):
                return True
            return None
    
        def allow_migrate(self, db, app_label, model_name=None, **hints):
            if app_label in self.route_app_labels:
                return db == settings.DMS_DB_ROUTER
            else if db == settings.DMS_DB_ROUTER:
                return False # Only apps in `route_app_labels` will be migrated to `dms_db`
            return None # Let other routers decide
    

    【讨论】:

    • 我希望你能回答,搜索了一些推特句柄,所以我可以 DM 你这个问题,但找不到。没关系。非常感谢。
    猜你喜欢
    • 2012-03-28
    • 2011-12-24
    • 1970-01-01
    • 2017-10-16
    • 2017-06-16
    • 1970-01-01
    • 1970-01-01
    • 2013-11-23
    • 2019-10-08
    相关资源
    最近更新 更多