fh_bash
fh_bash

Reputation: 1795

How can I force ModelForm to use specific database?

I have this ModelForm:

class ClienteForm(ModelForm):
   class Meta:
     model = Pessoa

   def __init__(self, *args, **kwargs):
     vUserProfile = kwargs.pop('vUserProfile', None)
     super(ClienteForm, self).__init__(*args, **kwargs)

How can I force to use a specific database?

I can't use db router, because the "specific" database is setting in my User profile, and I don't know how to get UserProfile in db-router class..

I know I can use in ClienteForm.save(using=XXX), but when I try ClienteForm.is_valid I got error, because django is try to use "default" database.

thanks

Upvotes: 1

Views: 110

Answers (1)

fh_bash
fh_bash

Reputation: 1795

Reply my own question...

The only way to get this right is make one middleware to get database name and work with locals, like this:

File: middleware.py

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, please let's me know!

Thanks to everybody.

Upvotes: 1

Related Questions