In my Django project I have a couple of applications, one of them is email_lists
and this application does a lot of data handling reading data from the Model Customers
. In my production environment I have two databases: default
and read-replica
. I would like all queries in a particular module to be made against the replica-set
database.
I can do that if I explicitly tell the query to do so:
def get_customers(self):
if settings.ENV == 'production':
customers = Customer.objects.using('read-replica').filter()
else:
customers = Customer.objects.filter()
but this module has more than 100 queries to the Customer
and other models. I also have queries to relations like:
def get_value(self, customer):
target_sessions = customer.sessions.filter(status='open')
carts = Cart.objects.filter(session__in=target_sessions)
the idea is that I want to avoid writing:
if settings.ENV == 'production':
instance = Model.objects.using('read-replica').filter()
else:
instance = Model.objects.filter()
for every query. There are other places in my project that do need to read from default
database so it can't be a global setting. I just need this module or file to read using the replica.
Is this possible in Django, are there any shortcuts ?
Thanks
You can read on django database routers for this, some good examples can be found online as well and they should be straightforward.
--
Another solution would be to modify the Model manager.
from django.db import models
class ReplicaRoutingManager(models.Manager):
def get_queryset(self):
queryset = super().get_queryset(self)
if settings.ENV == 'production':
return queryset.using('read-replica')
return queryset
class Customer(models.Model):
...
objects = models.Manager()
replica_objects = ReplicaRoutingManager()
with this, you can just use the normal Customer.objects.filter
and the manager should do the routing.
I still suggest going with the database router solution, and creating a custom logic in the class. But if the manager works for you, its fine.