在Django中使用两个数据库(一个只读)

时间:2019-07-09 14:25:42

标签: python django database multiple-databases

我正在使用两个数据库,一个数据库从另一个数据库读取数据,然后将数据写入另一个数据库。以下是我的Router类以及对设置的更改,但是对这个概念还不熟悉,有人可以在这方面有更多经验吗,确认它应该起作用或有助于进行编辑?

该应用程序名为“ myapp”,我已将只读数据库命名为“ readonly_db”,而我要写入的数据库是“默认”数据库。

    class MyappRouter:
        def db_for_read(self, model, **hints):
            if model._meta.app_label == 'myapp':
                return 'readonly_db'
            return None
        def db_for_write(self, model, **hints):
            if model._meta.app_label == 'myapp'
                return 'default'
            return None

        def allow_relation(self, obj1, obj2, **hints):
            if obj1._meta.app_label == obj2._meta.app_label:
                return True
            else:
                return False
            return None

        def allow_migrate(self, db, **hints):
            if db == 'default':
                return True
            elif db == 'readonly_db':
                return False
            return None
    DATABASE_ROUTERS = ['<path to>.myapprouter.py']
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': 'myapp' ,
            'USER': 'USER',
            'PASSWORD': 'PASSWORD',
            'HOST': 'LOCALHOST',
            'PORT': '5432'
        }
        'readonly_db': {
            'ENGINE': 'django_postgres_readonly'
            'NAME': 'READONLY'
            'USER': 'USER'
            'PASSWORD': 'PASSWORD'
            'HOST': 'LOCALHOST'
            'PORT': '5432'
    }

1 个答案:

答案 0 :(得分:2)

您的方法正确。我将分享当前正在运行的解决方案。

settings.py

USE_REPLICA = eval_env_as_boolean("USE_REPLICA", False)

DATABASES = {
    "default": {
        "ENGINE": os.getenv("DB_ENGINE", "django.db.backends.sqlite3"),
        "NAME": os.getenv("DB_DATABASE", os.path.join(BASE_DIR, "db.sqlite3")),
        "USER": os.getenv("DB_USER"),
        "HOST": os.getenv("DB_HOST"),
        "PORT": os.getenv("DB_PORT"),
        "PASSWORD": os.getenv("DB_PASSWORD"),
    }
}

DATABASES["default"]["CONN_MAX_AGE"] = int(os.getenv("DB_CONN_MAX_AGE", 0))  # type: ignore

if USE_REPLICA:
    DATABASES["replica"] = {
        "ENGINE": os.getenv("DB_ENGINE_REPLICA"),
        "NAME": os.getenv("DB_DATABASE_REPLICA"),
        "USER": os.getenv("DB_USER_REPLICA"),
        "HOST": os.getenv("DB_HOST_REPLICA"),
        "PORT": os.getenv("DB_PORT_REPLICA"),
        "PASSWORD": os.getenv("DB_PASSWORD_REPLICA"),
    }

    DATABASES["replica"]["CONN_MAX_AGE"] = int(os.getenv("DEFAULT_DB_CONN_MAX_AGE_REPLICA", 0))  # type: ignore
    DATABASE_ROUTERS = ["my_app.setup.db_routing.DatabaseRouter"]

db_routing.py

class DatabaseRouter:
    """
    A router to control all database operations on models in the
    auth application.
    """

    def db_for_read(self, model, **hints):
        """
        Always read from REPLICA database
        """
        return "replica"

    def db_for_write(self, model, **hints):
        """
        Always write to DEFAULT database
        """
        return "default"

    def allow_relation(self, obj1, obj2, **hints):
        """
        Objects from REPLICA and DEFAULT are de same, then True always
        """
        return True

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Only DEFAULT database
        """
        return db == "default"

基本上,您可以简化一下路由器

更新:

USE_REPLICA仅作为一个选项存在,因此我可以快速禁用读取的数据库。 Settings.py仅在系统启动时运行,因此仅在该变量存在时才在系统启动时添加副本配置。

关于CONN_MAX_AGE,您可以看到更多的herehere也在生产清单上。