在Django中实现DB Router的最佳方法是什么?

时间:2018-10-29 10:15:09

标签: django database

我已经在Django中实现了Automatic DB Routing,并使用了AWS Aurora for Database进行复制。我发现我的数据库存在较小的复制滞后,从而阻碍了流程。比方说,发生问题的原因是,当读取的查询集正在以“从属”执行时,然后在使用该查询集更新值时显示错误,例如“对该表的只读访问”。这意味着要进行更新,它应该路由到主数据库。

这是我的多个数据库的数据库设置:

DATABASES = {
    'master': {
        'ENGINE': 'django.db.backends.mysql',
        'STORAGE_ENGINE': 'MyISAM / INNODB / ETC',
        'NAME': 'db',
        'USER': 'master',
        'PASSWORD': 'master',
        'HOST': 'localhost',
        'PORT': '3306',

    },
    'slave': {
        'ENGINE': 'django.db.backends.mysql',
        'STORAGE_ENGINE': 'MyISAM / INNODB / ETC',
        'NAME': 'db',
        'USER': 'name',
        'PASSWORD': 'pass',
        'HOST': 'localhost',
        'PORT': '3306',

    },

    'slave2': {
        'ENGINE': 'django.db.backends.mysql',
        'STORAGE_ENGINE': 'MyISAM / INNODB / ETC',
        'NAME': 'db',
        'USER': 'name',
        'PASSWORD': 'pass',
        'HOST': 'localhost',
        'PORT': '3306',

    }

}


DATABASE_ROUTERS = ['path.to.AuthRouter']

请提供给我最好的方式来自动处理Django中的多个数据库路由。

"""
DB Router core class which auto selects required database configuration
"""
class AuthRouter:

    def db_for_read(self, model, **hints):
        """
        Reads go to a replica.
        """
        print 'db_for_read'
        print model
        return 'slave'

    def db_for_write(self, model, **hints):
        """
        Writes always go to master ie default.
        """
        print 'db_for_write'
        print model
        return 'master'

    def allow_relation(self, obj1, obj2, **hints):
        """
        Relations between objects are allowed if both objects are
        in the default/replica pool.
        """
        db_list = ('master', 'slave')
        if obj1._state.db in db_list and obj2._state.db in db_list:
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        All non-auth models end up in this pool.
        """
        return True

1 个答案:

答案 0 :(得分:0)

您可以拆分读取操作并隔离主数据库的写入操作,例如: AuthRouter应该调用主数据库,因为这是用户的最新信息。

class AuthRouter:

    def db_for_read(self, model, **hints):
        """
        Reads go to a replica.
        """
        return 'master'

    def db_for_write(self, model, **hints):
        """
        Writes always go to master ie default.
        """
        return 'master'

    def allow_relation(self, obj1, obj2, **hints):
        """
        Relations between objects are allowed if both objects are
        in the default/replica pool.
        """
        db_list = ('master', 'slave')
        if obj1._state.db in db_list and obj2._state.db in db_list:
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        All non-auth models end up in this pool.
        """
        return True
class PrimaryReplicaRouter(object):
    """
    A router to control all read/write database operations.
    """
    def db_for_read(self, model, **hints):
        """
        Reads go to a randomly-chosen replica.
        """
        return select_rand_db()

    def db_for_write(self, model, **hints):
        """
        Writes always go to primary.
        """
        return 'master'

    def allow_relation(self, obj1, obj2, **hints):
        """
        Relations between objects are allowed if both objects are
        in the primary/replica pool.
        """
        return True

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        All non-auth models end up in this pool.
        """
        return True


def select_rand_db():
    from numpy.random import choice
    """
    this function returns rand db or default if running tests
    :return:
    """

    return choice(['master', 'slave'], p=[0.5, 0.5])