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...)
createuses the default manager of yourAdminMeterLakemodel, which in turn uses the default db. One approach to solve this is to override your serializer'screatemethod to use the specific db you want, or change the default manager ofAdminMeterLaketo use your specific db