Hey, I actually opened a ticket about this a while ago:
We actually recently deployed a ‘monkey-patch’ to do this kind of stuff in our project:
If you’re only interested on overriding ORM queries, you could probably still it down to overriding the database router part:
import contextvars
from contextlib import contextmanager
_dbname_var = contextvars.ContextVar("dbname")
_readonly_var = contextvars.ContextVar("readonly")
@contextmanager
def db_override(dbname, readonly=False):
dbname_token = _dbname_var.set(dbname)
readonly_token = _readonly_var.set(readonly)
try:
yield
finally:
_dbname_var.reset(dbname_token)
_readonly_var.reset(readonly_token)
class OverrideRouter:
def db_for_read(self, *args, **kwargs):
if dbname := _dbname_var.get(None):
return dbname
def db_for_write(self, *args, **kwargs):
if dbname := _dbname_var.get(None):
if _readonly_var.get(False):
from django.db import InterfaceError
raise InterfaceError(f"current db context does not allows writes to '{dbname}'")
return dbname
However, any usage of transaction.atomic, connection.cursor or a lot of Django extensions usage might end up using the default DB (which is why I think routers right now are not that useful).