Exemple #1
0
class DatabaseWrapper(WRAPPED_BACKEND.DatabaseWrapper):
    def __init__(self, *args, **kwargs):
        super(DatabaseWrapper, self).__init__(*args, **kwargs)
        self.threadlocal = MultiTenantThreadlocal()

    def get_threadlocal(self):
        return self.threadlocal

    def _cursor(self):
        """Supplies a cursor, executing the `USE` statement if required.

        Ideally we'd override a get_new_connection DatabaseWrapper function,
        but _cursor() is as close as it gets.
        """
        cursor = super(DatabaseWrapper, self)._cursor()

        dbname = self.threadlocal.get_dbname()
        if not dbname:
            raise ImproperlyConfigured('dbname not set at cursor create time')

        # Cache the applied dbname as "mt_dbname" on the connection, avoiding
        # an extra execute() if already set.  Importantly, we assume no other
        # code in the app is executing `USE`.
        connection = cursor.cursor.connection
        connection_dbname = getattr(connection, 'mt_dbname', None)

        if connection_dbname != dbname:
            start_time = time.time()
            cursor.execute('USE `%s`;' % dbname)
            time_ms = int((time.time() - start_time) * 1000)
            LOGGER.debug('Applied dbname `%s` in %s ms' % (dbname, time_ms))
            connection.mt_dbname = dbname

        return cursor
class DatabaseWrapper(WRAPPED_BACKEND.DatabaseWrapper):
    def __init__(self, *args, **kwargs):
        super(DatabaseWrapper, self).__init__(*args, **kwargs)
        self.threadlocal = MultiTenantThreadlocal()

    def get_threadlocal(self):
        return self.threadlocal

    def _cursor(self):
        """Supplies a cursor, executing the `USE` statement if required.

        Ideally we'd override a get_new_connection DatabaseWrapper function,
        but _cursor() is as close as it gets.
        """
        cursor = super(DatabaseWrapper, self)._cursor()

        dbname = self.threadlocal.get_dbname()
        if not dbname:
            raise ImproperlyConfigured('dbname not set at cursor create time')

        # Cache the applied dbname as "mt_dbname" on the connection, avoiding
        # an extra execute() if already set.  Importantly, we assume no other
        # code in the app is executing `USE`.
        connection = cursor.cursor.connection
        connection_dbname = getattr(connection, 'mt_dbname', None)

        if connection_dbname != dbname:
            start_time = time.time()
            cursor.execute('USE `%s`;' % dbname)
            time_ms = int((time.time() - start_time) * 1000)
            LOGGER.debug('Applied dbname `%s` in %s ms' % (dbname, time_ms))
            connection.mt_dbname = dbname

        return cursor
class DatabaseWrapper(WRAPPED_BACKEND.DatabaseWrapper):
    def __init__(self, *args, **kwargs):
        super(DatabaseWrapper, self).__init__(*args, **kwargs)
        self.threadlocal = MultiTenantThreadlocal()

    def get_threadlocal(self):
        return self.threadlocal

    def create_cursor(self, name=None):
        cursor = self.connection.cursor()
        return CursorWrapper(cursor)

    def _cursor(self):
        """Supplies a cursor, executing the `USE` statement if required.

        Ideally we'd override a get_new_connection DatabaseWrapper function,
        but _cursor() is as close as it gets.
        """
        cursor = super(DatabaseWrapper, self)._cursor()

        db_name = self.threadlocal.get_db_name()
        if not db_name:
            # Django loads the settings after it tries to connect to mysql, when
            # running management commands If that's the case, update database
            # name manually
            update_database_from_env(
                super(DatabaseWrapper, self).get_connection_params()
            )
            db_name = self.threadlocal.get_db_name()
            if not db_name:
                raise ImproperlyConfigured("db_name not set at cursor create time")

        # Cache the applied db_name as "mt_db_name" on the connection, avoiding
        # an extra execute() if already set.  Importantly, we assume no other
        # code in the app is executing `USE`.
        connection = cursor.cursor.connection
        connection_db_name = getattr(connection, "mt_db_name", None)

        if connection_db_name != db_name:
            start_time = time.time()
            cursor.execute("USE `%s`;" % db_name)
            time_ms = int((time.time() - start_time) * 1000)
            LOGGER.debug("Applied db_name `%s` in %s ms", db_name, time_ms)
            connection.mt_db_name = db_name

        return cursor
Exemple #4
0
class DatabaseWrapper(WRAPPED_BACKEND.DatabaseWrapper):
    def __init__(self, *args, **kwargs):
        super(DatabaseWrapper, self).__init__(*args, **kwargs)
        self.threadlocal = MultiTenantThreadlocal()
        self.search_path_set = False

    def close(self):
        self.search_path_set = False
        super(DatabaseWrapper, self).close()

    def rollback(self):
        super(DatabaseWrapper, self).rollback()
        # Django's rollback clears the search path so we have to set it again the next time.
        self.search_path_set = False

    def get_threadlocal(self):
        return self.threadlocal

    def _cursor(self, name=None):
        """Supplies a cursor, selecting the schema if required.

        Ideally we'd override a get_new_connection DatabaseWrapper function,
        but _cursor() is as close as it gets.
        """
        if name:
            cursor = super(DatabaseWrapper, self)._cursor(name=name)
        else:
            cursor = super(DatabaseWrapper, self)._cursor()

        tenant_name = self.threadlocal.get_tenant_name()
        if not tenant_name:
            raise ImproperlyConfigured(
                'Tenant name not set at cursor create time.')

        # Cache the applied search_path.  Importantly, we assume no other
        # code in the app is executing `SET search_path`.
        if not self.search_path_set:
            # Named cursor can only be used once
            cursor_for_search_path = self.connection.cursor(
            ) if name else cursor
            # Nothing prevent tenant_name to be 'foo, public' to provide sharing of tables
            # (eg. to provide a common table of users).
            cursor_for_search_path.execute('SET search_path TO %s' %
                                           tenant_name)

            if name:
                cursor_for_search_path.close()

            self.search_path_set = True

        return cursor
Exemple #5
0
class DatabaseWrapper(WRAPPED_BACKEND.DatabaseWrapper):
    def __init__(self, *args, **kwargs):
        super(DatabaseWrapper, self).__init__(*args, **kwargs)
        self.threadlocal = MultiTenantThreadlocal()
        self.search_path_set = False

    def close(self):
        self.search_path_set = False
        super(DatabaseWrapper, self).close()

    def rollback(self):
        super(DatabaseWrapper, self).rollback()
        # Django's rollback clears the search path so we have to set it again the next time.
        self.search_path_set = False

    def get_threadlocal(self):
        return self.threadlocal

    def _cursor(self, name=None):
        """Supplies a cursor, selecting the schema if required.

        Ideally we'd override a get_new_connection DatabaseWrapper function,
        but _cursor() is as close as it gets.
        """
        if name:
            cursor = super(DatabaseWrapper, self)._cursor(name=name)
        else:
            cursor = super(DatabaseWrapper, self)._cursor()

        tenant_name = self.threadlocal.get_tenant_name()
        if not tenant_name:
            raise ImproperlyConfigured('Tenant name not set at cursor create time.')

        # Cache the applied search_path.  Importantly, we assume no other
        # code in the app is executing `SET search_path`.
        if not self.search_path_set:
            # Named cursor can only be used once
            cursor_for_search_path = self.connection.cursor() if name else cursor
            # Nothing prevent tenant_name to be 'foo, public' to provide sharing of tables
            # (eg. to provide a common table of users).
            cursor_for_search_path.execute('SET search_path TO %s' % tenant_name)

            if name:
                cursor_for_search_path.close()

            self.search_path_set = True

        return cursor
Exemple #6
0
 def __init__(self, *args, **kwargs):
     super(DatabaseWrapper, self).__init__(*args, **kwargs)
     self.threadlocal = MultiTenantThreadlocal()
Exemple #7
0
 def __init__(self, *args, **kwargs):
     super(DatabaseWrapper, self).__init__(*args, **kwargs)
     self.threadlocal = MultiTenantThreadlocal()
 def __init__(self, *args, **kwargs):
     super(DatabaseWrapper, self).__init__(*args, **kwargs)
     self.threadlocal = MultiTenantThreadlocal()
     if not self.threadlocal.get_dbname():
         self.threadlocal.set_dbname(self.settings_dict['NAME'])
Exemple #9
0
try:
    # Django versions >= 1.9
    from django.utils.module_loading import import_module
except ImportError:
    # Django versions < 1.9
    from django.utils.importlib import import_module

from db_multitenant.mapper import TenantMapper

_CACHED_MAPPER = None

import os

from django.db import connection
from db_multitenant.threadlocal import MultiTenantThreadlocal
my_local_global = MultiTenantThreadlocal()

def get_mode():
    return getattr(settings, 'MULTI_TENANT_MODE', "SCHEMA")

def get_threadlocal():
    if get_mode() == "SCHEMA":
        return connection.get_threadlocal()
    else: # mode == "DATABASE":
        return my_local_global

def get_default_tenant_name():
    return getattr(settings, 'DEFAULT_TENANT_NAME', "devnull")

def update_database_from_env(db_dict):
    from django.db import connection