I recommend to create context manager. That will allow to effectively control DB connections in future:
- Add DB router to
config/settings.py
...
DATABASE_ROUTERS = [
'config.routers.DynamicDatabaseRouter',
]
...
- Create
DynamicDatabaseRouter
in config/routers.py
:
from contextvars import ContextVar
active_db = ContextVar("DB to use", default=None)
def get_active_db():
# return default connection if not set
db = active_db.get(None)
return db if db else 'default'
def set_active_db(connection_name):
return active_db.set(connection_name)
class DynamicDatabaseRouter:
@staticmethod
def _get_db(*args, **kwargs):
db = get_active_db()
return db
db_for_read = _get_db
db_for_write = _get_db
- Add context manager into
config/context.py
:
from contextlib import ContextDecorator
from config.routers import set_active_db
class db(ContextDecorator):
def __init__(self, connection_name):
self.connection_name = connection_name
def __enter__(self):
set_active_db(connection_name)
return self
def __exit__(self, *exc):
set_active_db(None)
return False
And your class should be updated to:
from config.context import db
class AdminView(
mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
serializer_class = AdminMeterLakeSerializer
queryset = AdminMeterLake.objects.using('testdb').all()
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
with db('testdb'):
return self.create(request.data, *args, **kwargs)
The flow is:
- When you run
with db('testdb')
the __enter__
method is called
active_db
context variable value will be updated to testdb
- database router read
active_db
value and use testdb
connection
- When operation is complete
__exit__
will be called and context variable value will be reverted to None
*
- if
active_db
value is None
router will return default
connection
OR 1
You may simply use django-dynamic-db-router
Also this information may be useful
OR 2
You may set custom Manager
class for database Model
:
from django.db import models
class AdminMeterLake(models.Model):
...
col_name_1 = models.CharField(max_length=50)
col_name_2 = models.CharField(max_length=50)
...
objects = models.Manager().using('testdb')
In this case testdb
will be used by default and you will be able to set queryset = AdminMeterLake.objects.all()
instead of queryset = AdminMeterLake.objects.using('testdb').all()
models.Manager().using('testdb')
way is didn't tested by me and it is just theoretical solution (but it should work I guess...)