Last active
May 5, 2019 07:29
-
-
Save tobiasmcnulty/6314224 to your computer and use it in GitHub Desktop.
Django database router, based on django-balancer, that sends reads for the specified models to the RoundRobinMasterSlaveRouter router in django-balancer. Uses thread locals to determine whether or not the it has been enabled for the current request. Will raise an exception if views or other code attempt to use it for write queries.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from functools import wraps | |
from routers import ForceReadForModelsRouter | |
__all__ = ['uses_forced_read_router'] | |
def uses_forced_read_router(func): | |
@wraps(func) | |
def wrapper(req, *args, **kwargs): | |
try: | |
ForceReadForModelsRouter.enable() | |
return func(req, *args, **kwargs) | |
finally: | |
ForceReadForModelsRouter.disable() | |
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import threading | |
from balancer.routers import RoundRobinMasterSlaveRouter | |
class ForceReadForModelsRouter(RoundRobinMasterSlaveRouter): | |
""" | |
Router that sends reads for the specified models to the | |
RoundRobinMasterSlaveRouter router in django-balancer. Uses thread locals | |
to determine whether or not the it has been enabled for the current request. | |
Will raise an exception if views or other code attempt to use it for write | |
queries. | |
""" | |
_locals = threading.local() | |
app_models = { | |
'appname': [ | |
'Model1', | |
'Model2', | |
], | |
} | |
@classmethod | |
def enable(cls): | |
cls._locals.enabled = True | |
@classmethod | |
def disable(cls): | |
cls._locals.enabled = False | |
@classmethod | |
def is_enabled(cls): | |
return getattr(cls._locals, 'enabled', False) | |
def _should_handle(self, model): | |
return ForceReadForModelsRouter.is_enabled() and\ | |
model._meta.app_label in self.app_models and\ | |
model._meta.object_name in self.app_models[model._meta.app_label] | |
def db_for_read(self, model, **hints): | |
if self._should_handle(model): | |
return super(ForceReadForModelsRouter, self).db_for_read(model, **hints) | |
def db_for_write(self, model, **hints): | |
if self._should_handle(model): | |
model_name = '.'.join([model._meta.app_label, | |
model._meta.object_name]) | |
raise ValueError('The {0} model is marked as read-only'.format(model_name)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment