Início > Develop, Django, Python > HowTo Django: One database for auth, and each user connect to different database.

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

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!

Anúncios
  1. Nenhum comentário ainda.
  1. No trackbacks yet.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: