public
Created

  • Download Gist
multidb.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
"""
With :class:`~multidb.SlaveQuerySet` and :class:`~multidb.SlaveMixin`, all read
queries will go to a slave database; all inserts, updates, and deletes will do
to the ``default`` database.
 
First, define ``SLAVE_DATABASES`` in your settings. It should be a list of
database aliases that can be found in ``DATABASES``::
 
DATABASES = {
'default': {...},
'shadow-1': {...},
'shadow-2': {...},
}
SLAVE_DATABASES = ['shadow-1', 'shadow-2']
 
Then add a :class:`multidb.SlaveManager` to your model and inherit from
:class:`multidb.SlaveMixin`::
 
from django.db import models
 
import multidb
 
 
class Slurpee(multidb.SlaveMixin, models.Model):
number = models.IntegerField()
 
objects = multidb.SlaveManager()
 
Instead of a normal :class:`~django.db.models.query.QuerySet`, the
``SlaveManager`` will return a ``SlaveQuerySet`` that sends all traffic to one
of the slaves.
 
The slave databases will be chosen in round-robin fashion.
"""
import itertools
import random
 
from django.conf import settings
from django.db import models, DEFAULT_DB_ALIAS
 
 
if getattr(settings, 'SLAVE_DATABASES'):
# Shuffle the list so the first slave db isn't slammed during startup.
dbs = list(settings.SLAVE_DATABASES)
random.shuffle(dbs)
slaves = itertools.cycle(dbs)
else:
slaves = itertools.repeat(DEFAULT_DB_ALIAS)
 
 
class SlaveManager(models.Manager):
"""Returns a SlaveQuerySet instead of a normal QuerySet."""
 
def get_query_set(self):
return SlaveQuerySet(self.model)
 
 
class SlaveQuerySet(models.query.QuerySet):
"""
Sends SELECTs to one of the slave databases in a round-robin schedule.
 
A specific database can be selected with the ``using`` statement.
"""
 
@property
def db(self):
if self._db is None:
self._db = slaves.next()
return self._db
 
 
class SlaveMixin(object):
"""Sends all INSERTs, UPDATEs, and DELETEs to the default database."""
 
def save(self, force_insert=False, force_update=False, using=None):
using = using or DEFAULT_DB_ALIAS
return super(SlaveMixin, self).save(force_insert, force_update, using)
 
def delete(self, using=None):
using = using or DEFAULT_DB_ALIAS
return super(SlaveMixin, self).delete(using)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.