Search code examples
pythondjangodjango-database

Django multiple DB how to write router


I've got two DB, I've written a router.py that correctly manage write and read, but if the read db the default is down I cannot access also the write db getting the

class TestRouter(object):

    def db_for_read(self, model, **hints):

        if model._meta.app_label == 'read_app':
            return 'default'
        if model._meta.app_label == 'write_app':
            return 'write_db'        
        return None

    def db_for_write(self, model, **hints):

        if model._meta.app_label == 'write_app':
            return 'write_db'
        return None

and in settings.py:

DATABASE_ROUTERS = ['prj.dbrouter.TestRouter', ]

this is the error:

cnn = _connect(dsn, connection_factory=connection_factory, async=async)
OperationalError: could not connect to server: Connection refused Is the server running on host "192.168.2.1" and accepting TCP/IP connections on port 5432?

is there a way to say to django to ignore failure in connection to default db?


Solution

  • Error shows that the database to which you want to connect is not accepting request or listening from host "192.168.2.1".

    In postgresql.conf file, change listen_addresses = '*'

    Lemme elaborate what exactly you should do,

    1. Add the database information in your settings.py and also information about the routers.py :

    settings.py

    DATABASES = {
        'default': {},
        'master': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': '',
            'USER': '',
            'PASSWORD': '',
            'HOST': '',
            'PORT': 5432,
        },
        'slave': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': '',
            'USER': '',
            'PASSWORD': '',
            'HOST': '',
            'PORT': 5432,
        }
    }
    SLAVE_DATABASES = ['slave']
    
    DATABASE_ROUTERS = ['path.to.your.routers.MasterSlaveRouter']
    
    1. Create the routers.py which will handle switching the read and write request among the database mentioned in settings :

    routers.py

    from django.conf import settings
    import socket
    
    
    def test_connection_to_db(database_name):
        try:
            db_definition = getattr(settings, 'DATABASES')[database_name]
            s = socket.create_connection(
                (db_definition['HOST'], db_definition['PORT']), 5)
            s.close()
            return True
        except:
            return False
    
    
    class MasterSlaveRouter(object):
        def db_for_read(self, model, **hints):
            """
            Reads go to a randomly-chosen slave.
            """
            if test_connection_to_db('master'):
                return 'master'
            return 'slave'
    
        def db_for_write(self, model, **hints):
            """
            Writes always go to master.
            """
            if test_connection_to_db('master'):
                return 'master'
            return 'slave'
    
        def allow_relation(self, obj1, obj2, **hints):
            """
            Relations between objects are allowed if both objects are
            in the master/slave 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, model):
            """
            All non-auth models end up in this pool.
            """
            return True
    

    So now if your master is down and slave is up. Request will be transferred accordingly and vice-versa. Make sure any one database is up.

    HTH! :)