11

I am writing a multi-tenant application with python-django.

I want to set database connection based on each request.I thought i could write a middleware where we set the database to be used for that particular database.

import re
from django.db import connections

class SetTenantDatabase(object):
    def process_request(self, request):
        pattern = re.compile("\\b(http://|https://|www.|.com|8000|:|//)\\W\\d+", re.I)
        words = request.get_host()        
        db_name = [pattern.sub("", words)][0].split('.')[0]
        connections.databases['new-alias'] = { 
        'default': {
                    'ENGINE': 'django.db.backends.postgresql_psycopg2',
                    'NAME': 'store1',
                    'USER': 'xxx',
                    'PASSWORD': 'xxx',
                    'HOST': '127.0.0.1',
    } 
                                              }
        conn = connections['new-alias']
        return None

but this is not working.How should i do this.Is the approach wrong or is the solution feasible, and lastly How?

1
  • The database is set by the router per request, if you mean per-session, that's different. Commented Jun 14, 2022 at 14:21

2 Answers 2

31

this is the answer, hope it helps someone in future:

import re
import threading 
request_cfg = threading.local()


class RouterMiddleware(object):
    def process_request( self, request):
        pattern = re.compile("\\b(http://|https://|www.|.com|8000|:|//)\\W\\d+", re.I)
        words = request.get_host()        
        db_name = [pattern.sub("", words)][0].split('.')[0]
        request_cfg.cfg = db_name
        return None

    def process_response( self, request, response ):
        if hasattr( request_cfg, 'cfg' ):
            del request_cfg.cfg
        return response


class DatabaseRouter (object):
    def _default_db( self ):
        if hasattr( request_cfg, 'cfg' ):
            return request_cfg.cfg
        else:
            return 'default'

    def db_for_read( self, model, **hints ):
        return self._default_db()

    def db_for_write( self, model, **hints ):
        return self._default_db()

Thanks

Sign up to request clarification or add additional context in comments.

3 Comments

if possible could you please add some explanation to your code. It will be helpful to newbies like me
Can you explain about threading.Local and how will it manage two simultaneous transactions for different db
I'll try to provide some explanation for this one. You can have these classes in some file in your app like middlewares.py. Then you add the router middleware to the list 'MIDDLEWARE' in settings.py and the database router in a list called 'DATABASE_ROUTERS'. Once you have those the middleware starts intercepting the requests packets.
1

Maybe you can use:

https://docs.djangoproject.com/en/dev/topics/db/multi-db/#manually-selecting-a-database-for-a-queryset

Entity.objects.using('context1').all()
Entity.objects.using('context2').all()

To select/use a database depending on the request. You can define multiple DBs in the configurartion:

DATABASES = {
    'context1': {
        'NAME': 'context1',
        'ENGINE': 'db.engine.to.use',
        'USER': 'xxx',
        'PASSWORD': 'xxx'
    },
    'context2': {
        'NAME': 'context2',
        'ENGINE': 'db.engine.to.use',
        'USER': 'xxx',
        'PASSWORD': 'xxx'
    }
}

1 Comment

i am creating database on fly .. so it wont be in DATABASES settings

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.