Arquivo

Posts Tagged ‘django’

HowTo Django: One database for auth, and each user connect to different database.

2 de agosto de 2013 Deixe um comentário

First of all, this is my First post write in English in my blog, so, excuse me for any errors.

The problem:

I have one database named auth.db, in this app Django will store only users, sessions, auth dbs etc..  Each user will connect to a different database, named in dbname field stored in UserProfile, all other models connect to this database. So how can I do this? Using  mymodel.objects(using=UserProfile.dbname).all  works in some type of code, but when you in view call myForm.is_valid(), django try to validate using the “default” database. Using only db-route doesn’t work, because in db-route class I don’t have access to the request and for consequence I can’t get UserProfile.

So… after ask in stackoverflow and some time spent in code, I found a solution. And I describe right now:

The only way to get this right is make one middleware to get database name and work with locals thread, create one file named middleware.py, and put this:

from threading import local
from django.contrib.sessions.models import Session
from django.contrib.auth.models import User
from web_core.models import UserProfile

my_local_global = local()

class CustomerMiddleware(object):
def process_request(self, request):
my_local_global.database_name = get_database_name(request)

    def get_database_name(request):
       session_key = request.session.session_key
try:
session = Session.objects.get(session_key=session_key)
uid = session.get_decoded().get('_auth_user_id')
user = User.objects.get(pk=uid)

profile = UserProfile.objects.get(pk=uid)

if profile:
return profile.dbname
else:
return None
except:
return None

after this, add middleware.py in your settings.py:

MIDDLEWARE_CLASSES = (
(..)
    'middleware.CustomerMiddleware',
)

to finish, make one more file to get db router:

File: authrouter:

class PadraoRouter(object):
    def db_for_read(self, model, **hints):
        from middleware import my_local_global
        return my_local_global.database_name

    def db_for_write(self, model, **hints):
        from middleware import my_local_global
        return my_local_global.database_name

    def allow_relation(self, obj1, obj2, **hints):
        return None

    def allow_syncdb(self, db, model):
        return True

class AuthRouter(object):
    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'auth':
            return 'auth_db'
        if model._meta.app_label == 'sessions':
            return 'auth_db'
        if model._meta.app_label == 'web_core':
            return 'auth_db'
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label == 'auth':
            return 'auth_db'
        if model._meta.app_label == 'sessions':
            return 'auth_db'
        if model._meta.app_label == 'web_core':
            return 'auth_db'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        if obj1._meta.app_label == 'auth' or\
           obj2._meta.app_label == 'auth':
            return True
        if obj1._meta.app_label == 'sessions' or\
           obj2._meta.app_label == 'sessions':
            return True
        if obj1._meta.app_label == 'web_core' or\
           obj2._meta.app_label == 'web_core':
            return True
        return None

    def allow_syncdb(self, db, model):
        if db == 'auth_db':
            return model._meta.app_label == 'auth'
        elif model._meta.app_label == 'auth':
            return False
        return None

NOTE: I need to put import in each def, because Django 1.5.1 has a bug, if you put import into top of file.. cycle imports..

after this, change again your settings.py to add the router:

DATABASE_ROUTERS = ['authrouter.AuthRouter',
                    'authrouter.PadraoRouter']

Remember:

I make this way, because I have one database, only for auth.. each user can access a different database, depending what is save in dbname field.

If you have other solution or some questions, please let’s me know in comments!