Search code examples
djangopostgresqldjango-modelsdjango-database

Django specify which database to use for module


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


Solution

  • 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.