import random

from django.db.utils import DEFAULT_DB_ALIAS
from django.conf import settings


class ReplicationRouter(object):
    def __init__(self):
        self.state_stack = ['master']
        self._state_change_enabled = True

    def set_state_change(self, enabled):
        self._state_change_enabled = enabled

    def state(self):
        '''
        Current state of routing: 'master' or 'slave'.
        '''
        return self.state_stack[-1]

    def use_state(self, state):
        '''
        Switches router into a new state. Requires a paired call
        to 'revert' for reverting to previous state.
        '''
        if not self._state_change_enabled:
            state = self.state()
        self.state_stack.append(state)
        return self

    def revert(self):
        '''
        Reverts wrapper state to a previous value after calling
        'use_state'.
        '''
        self.state_stack.pop()

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

    def db_for_read(self, model, **hints):
        if self.state() == 'master':
            return self.db_for_write(model, **hints)
        slaves = getattr(settings, 'DATABASE_SLAVES', [DEFAULT_DB_ALIAS])
        return random.choice(slaves)

import random

from django.db import connections
from django.db.utils import DEFAULT_DB_ALIAS
from django.conf import settings


def is_alive(db):
    try:
        if db.connection is not None and hasattr(db.connection, 'ping'):
            db.connection.ping()
        else:
            db.cursor()
        return True
    except StandardError:
        return False


class ReplicationRouter(object):
    def __init__(self):
        self.state_stack = ['master']
        self._state_change_enabled = True

    def set_state_change(self, enabled):
        self._state_change_enabled = enabled

    def state(self):
        '''
        Current state of routing: 'master' or 'slave'.
        '''
        return self.state_stack[-1]

    def use_state(self, state):
        '''
        Switches router into a new state. Requires a paired call
        to 'revert' for reverting to previous state.
        '''
        if not self._state_change_enabled:
            state = self.state()
        self.state_stack.append(state)
        return self

    def revert(self):
        '''
        Reverts wrapper state to a previous value after calling
        'use_state'.
        '''
        self.state_stack.pop()

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

    def db_for_read(self, model, **hints):
        if self.state() == 'master':
            return self.db_for_write(model, **hints)
        slaves = getattr(settings, 'DATABASE_SLAVES', [DEFAULT_DB_ALIAS])
        random.shuffle(slaves)
        for slave in slaves:
            if is_alive(connections[slave]):
                return slave
        else:
            return DEFAULT_DB_ALIAS

Check if slaves are alive and fallback to other slaves and eventually to master.
Check if slaves are alive and fallback to other slaves and eventually to master.

  import random
  
+ from django.db import connections
  from django.db.utils import DEFAULT_DB_ALIAS
  from django.conf import settings
+ 
+ 
+ def is_alive(db):
+     try:
+         if db.connection is not None and hasattr(db.connection, 'ping'):
+             db.connection.ping()
+         else:
+             db.cursor()
+         return True
+     except StandardError:
+         return False
  
  
  class ReplicationRouter(object):
      def __init__(self):
          self.state_stack = ['master']
          self._state_change_enabled = True
  
      def set_state_change(self, enabled):
          self._state_change_enabled = enabled
  
      def state(self):
          '''
          Current state of routing: 'master' or 'slave'.
          '''
          return self.state_stack[-1]
  
      def use_state(self, state):
          '''
          Switches router into a new state. Requires a paired call
          to 'revert' for reverting to previous state.
          '''
          if not self._state_change_enabled:
              state = self.state()
          self.state_stack.append(state)
          return self
  
      def revert(self):
          '''
          Reverts wrapper state to a previous value after calling
          'use_state'.
          '''
          self.state_stack.pop()
  
      def db_for_write(self, model, **hints):
          return DEFAULT_DB_ALIAS
  
      def db_for_read(self, model, **hints):
          if self.state() == 'master':
              return self.db_for_write(model, **hints)
          slaves = getattr(settings, 'DATABASE_SLAVES', [DEFAULT_DB_ALIAS])
-         return random.choice(slaves)
+         random.shuffle(slaves)
+         for slave in slaves:
+             if is_alive(connections[slave]):
+                 return slave
+         else:
+             return DEFAULT_DB_ALIAS
  
Check if slaves are alive and fallback to other slaves and eventually to master.
## Code Before:
import random

from django.db.utils import DEFAULT_DB_ALIAS
from django.conf import settings


class ReplicationRouter(object):
    def __init__(self):
        self.state_stack = ['master']
        self._state_change_enabled = True

    def set_state_change(self, enabled):
        self._state_change_enabled = enabled

    def state(self):
        '''
        Current state of routing: 'master' or 'slave'.
        '''
        return self.state_stack[-1]

    def use_state(self, state):
        '''
        Switches router into a new state. Requires a paired call
        to 'revert' for reverting to previous state.
        '''
        if not self._state_change_enabled:
            state = self.state()
        self.state_stack.append(state)
        return self

    def revert(self):
        '''
        Reverts wrapper state to a previous value after calling
        'use_state'.
        '''
        self.state_stack.pop()

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

    def db_for_read(self, model, **hints):
        if self.state() == 'master':
            return self.db_for_write(model, **hints)
        slaves = getattr(settings, 'DATABASE_SLAVES', [DEFAULT_DB_ALIAS])
        return random.choice(slaves)

## Instruction:
Check if slaves are alive and fallback to other slaves and eventually to master.
## Code After:
import random

from django.db import connections
from django.db.utils import DEFAULT_DB_ALIAS
from django.conf import settings


def is_alive(db):
    try:
        if db.connection is not None and hasattr(db.connection, 'ping'):
            db.connection.ping()
        else:
            db.cursor()
        return True
    except StandardError:
        return False


class ReplicationRouter(object):
    def __init__(self):
        self.state_stack = ['master']
        self._state_change_enabled = True

    def set_state_change(self, enabled):
        self._state_change_enabled = enabled

    def state(self):
        '''
        Current state of routing: 'master' or 'slave'.
        '''
        return self.state_stack[-1]

    def use_state(self, state):
        '''
        Switches router into a new state. Requires a paired call
        to 'revert' for reverting to previous state.
        '''
        if not self._state_change_enabled:
            state = self.state()
        self.state_stack.append(state)
        return self

    def revert(self):
        '''
        Reverts wrapper state to a previous value after calling
        'use_state'.
        '''
        self.state_stack.pop()

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

    def db_for_read(self, model, **hints):
        if self.state() == 'master':
            return self.db_for_write(model, **hints)
        slaves = getattr(settings, 'DATABASE_SLAVES', [DEFAULT_DB_ALIAS])
        random.shuffle(slaves)
        for slave in slaves:
            if is_alive(connections[slave]):
                return slave
        else:
            return DEFAULT_DB_ALIAS
