Ticket #4747: mymultidb_trunk7534_20080521.diff

File mymultidb_trunk7534_20080521.diff, 137.3 KB (added by Koen Biermans <koen.biermans@…>, 16 years ago)

new attempt to generate correct diff

  • django/test/utils.py

     
    11import sys, time, os
    2 from django.conf import settings
    3 from django.db import connection, get_creation_module
     2from django.conf import settings, UserSettingsHolder
     3from django.db import connections, get_creation_module, _default
    44from django.core import mail
    55from django.core.management import call_command
    66from django.dispatch import dispatcher
     
    7878    elif hasattr(connection.connection, "set_isolation_level"):
    7979        connection.connection.set_isolation_level(0)
    8080
    81 def get_mysql_create_suffix():
     81def get_mysql_create_suffix(settings):
    8282    suffix = []
    83     if settings.TEST_DATABASE_CHARSET:
    84         suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET)
    85     if settings.TEST_DATABASE_COLLATION:
    86         suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION)
     83    if settings.DATABASE_CHARSET:
     84        suffix.append('CHARACTER SET %s' % settings.DATABASE_CHARSET)
     85    if settings.DATABASE_COLLATION:
     86        suffix.append('COLLATE %s' % settings.DATABASE_COLLATION)
    8787    return ' '.join(suffix)
    8888
    8989def get_postgresql_create_suffix():
    90     assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time."
    91     if settings.TEST_DATABASE_CHARSET:
    92         return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET
     90    assert settings.DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time."
     91    if settings.DATABASE_CHARSET:
     92        return "WITH ENCODING '%s'" % settings.DATABASE_CHARSET
    9393    return ''
    9494
    9595def create_test_db(verbosity=1, autoclobber=False):
     96
     97    if settings.DATABASE_ENGINE == "sqlite3":
     98        if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:":
     99            TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
     100        else:
     101            TEST_DATABASE_NAME = ":memory:"
     102    else:
     103        if settings.TEST_DATABASE_NAME:
     104            TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
     105        else:
     106            TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
     107
     108    settings.DATABASE_NAME = TEST_DATABASE_NAME
     109    settings.DATABASE_CHARSET = settings.TEST_DATABASE_CHARSET
     110    settings.DATABASE_COLLATION = settings.TEST_DATABASE_COLLATION
     111
     112    # default database
     113    _create_test_db(settings, verbosity=verbosity, autoclobber=autoclobber)
     114
     115    # other databases
     116    settings.OTHER_DATABASES = settings.TEST_OTHER_DATABASES
     117    for db in settings.OTHER_DATABASES:
     118        info = settings.OTHER_DATABASES[db]
     119        database = UserSettingsHolder(settings)
     120        for k, v in info.items():
     121            setattr(database, k, v)
     122        _create_test_db(database, verbosity=verbosity, autoclobber=autoclobber, connection_name=db)
     123
     124##    for cnx in connections:
     125##        connections[cnx].connection.close()
     126
     127    call_command('syncdb', verbosity=verbosity, interactive=False)
     128
     129    if settings.CACHE_BACKEND.startswith('db://'):
     130        cache_name = settings.CACHE_BACKEND[len('db://'):]
     131        call_command('createcachetable', cache_name)
     132
     133    # Get a cursor (even though we don't need one yet). This has
     134    # the side effect of initializing the test database.
     135##    for cnx in connections:
     136##        cursor = connections[cnx].connection.cursor()
     137##    cursor = connection.cursor()
     138
     139    return TEST_DATABASE_NAME
     140
     141def _create_test_db(settings, verbosity=1, autoclobber=False, connection_name=_default):
    96142    """
    97143    Creates a test database, prompting the user for confirmation if the
    98144    database already exists. Returns the name of the test database created.
    99145    """
     146    connection = connections[connection_name].connection
    100147    # If the database backend wants to create the test DB itself, let it
    101     creation_module = get_creation_module()
     148    creation_module = connections[connection_name].get_creation_module()
    102149    if hasattr(creation_module, "create_test_db"):
    103150        creation_module.create_test_db(settings, connection, verbosity, autoclobber)
    104151        return
     
    109156    # in-memory database. Using the TEST_DATABASE_NAME setting you can still choose
    110157    # to run on a physical database.
    111158    if settings.DATABASE_ENGINE == "sqlite3":
    112         if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:":
    113             TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
     159        if settings.DATABASE_NAME != ":memory:":
    114160            # Erase the old test database
    115161            if verbosity >= 1:
    116162                print "Destroying old test database..."
    117             if os.access(TEST_DATABASE_NAME, os.F_OK):
     163            if os.access(settings.DATABASE_NAME, os.F_OK):
    118164                if not autoclobber:
    119                     confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)
     165                    confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % settings.DATABASE_NAME)
    120166                if autoclobber or confirm == 'yes':
    121167                  try:
    122168                      if verbosity >= 1:
    123169                          print "Destroying old test database..."
    124                       os.remove(TEST_DATABASE_NAME)
     170                      os.remove(settings.DATABASE_NAME)
    125171                  except Exception, e:
    126172                      sys.stderr.write("Got an error deleting the old test database: %s\n" % e)
    127173                      sys.exit(2)
     
    130176                    sys.exit(1)
    131177            if verbosity >= 1:
    132178                print "Creating test database..."
    133         else:
    134             TEST_DATABASE_NAME = ":memory:"
    135179    else:
    136180        suffix = {
    137181            'postgresql': get_postgresql_create_suffix,
    138182            'postgresql_psycopg2': get_postgresql_create_suffix,
    139183            'mysql': get_mysql_create_suffix,
    140184            'mysql_old': get_mysql_create_suffix,
    141         }.get(settings.DATABASE_ENGINE, lambda: '')()
    142         if settings.TEST_DATABASE_NAME:
    143             TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
    144         else:
    145             TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
     185        }.get(settings.DATABASE_ENGINE, lambda: '')(settings)
    146186
     187        connection = connections[connection_name].connection
    147188        qn = connection.ops.quote_name
    148189
    149190        # Create the test database and connect to it. We need to autocommit
     
    172213                print "Tests cancelled."
    173214                sys.exit(1)
    174215
    175     connection.close()
    176     settings.DATABASE_NAME = TEST_DATABASE_NAME
    177216
    178     call_command('syncdb', verbosity=verbosity, interactive=False)
     217def destroy_test_db(old_database_name, old_databases, verbosity=1):
     218    if verbosity >= 1:
     219        print "Destroying test database(s)..."
     220##    connection.close()
     221    for cnx in connections.keys():
     222        connections[cnx].close()
     223##        connections.reset()
     224    TEST_DATABASE_NAME = settings.DATABASE_NAME
     225    settings.DATABASE_NAME = old_database_name
     226    _destroy_test_db(settings, TEST_DATABASE_NAME, verbosity=verbosity)
     227    TEST_OTHER_DATABASES = settings.OTHER_DATABASES
     228    settings.OTHER_DATABASES = old_databases
     229    for db in TEST_OTHER_DATABASES:
     230        info = TEST_OTHER_DATABASES[db]
     231        database = UserSettingsHolder(settings)
     232        for k, v in info.items():
     233            setattr(database, k, v)
     234        if db in old_databases:
     235            _destroy_test_db(database, info['DATABASE_NAME'], verbosity=verbosity, connection_name=db)
    179236
    180     if settings.CACHE_BACKEND.startswith('db://'):
    181         cache_name = settings.CACHE_BACKEND[len('db://'):]
    182         call_command('createcachetable', cache_name)
    183 
    184     # Get a cursor (even though we don't need one yet). This has
    185     # the side effect of initializing the test database.
    186     cursor = connection.cursor()
    187 
    188     return TEST_DATABASE_NAME
    189 
    190 def destroy_test_db(old_database_name, verbosity=1):
     237def _destroy_test_db(settings, TEST_DATABASE_NAME, verbosity=1, connection_name=_default):
     238    connection = connections[connection_name].connection
    191239    # If the database wants to drop the test DB itself, let it
    192     creation_module = get_creation_module()
     240    creation_module = connections[connection_name].get_creation_module()
    193241    if hasattr(creation_module, "destroy_test_db"):
    194242        creation_module.destroy_test_db(settings, connection, old_database_name, verbosity)
    195243        return
    196244
    197     if verbosity >= 1:
    198         print "Destroying test database..."
    199     connection.close()
    200     TEST_DATABASE_NAME = settings.DATABASE_NAME
    201     settings.DATABASE_NAME = old_database_name
    202245    if settings.DATABASE_ENGINE == "sqlite3":
    203246        if TEST_DATABASE_NAME and TEST_DATABASE_NAME != ":memory:":
    204247            # Remove the SQLite database file
    205             os.remove(TEST_DATABASE_NAME)
     248##            os.remove(TEST_DATABASE_NAME)
     249            pass
    206250    else:
    207251        # Remove the test database to clean up after
    208252        # ourselves. Connect to the previous database (not the test database)
  • django/test/simple.py

     
    138138    for test in extra_tests:
    139139        suite.addTest(test)
    140140
    141     old_name = settings.DATABASE_NAME
     141    old_database_name = settings.DATABASE_NAME
     142    old_other_databases = settings.OTHER_DATABASES
    142143    create_test_db(verbosity, autoclobber=not interactive)
    143144    result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
    144     destroy_test_db(old_name, verbosity)
     145    destroy_test_db(old_database_name, old_other_databases, verbosity)
    145146   
    146147    teardown_test_environment()
    147148   
  • django/db/models/sql/where.py

     
    44import datetime
    55
    66from django.utils import tree
    7 from django.db import connection
    87from django.db.models.fields import Field
    98from django.db.models.query_utils import QueryWrapper
    109from datastructures import EmptyResultSet, FullResultSet
    1110
     11from copy import deepcopy
     12
    1213# Connection types
    1314AND = 'AND'
    1415OR = 'OR'
     
    2627    """
    2728    default = AND
    2829
     30    def __init__(self, connection, *args, **kwargs):
     31        self.connection = connection
     32        super(WhereNode, self).__init__(*args, **kwargs)
     33
     34    def __deepcopy__(self, memo):
     35        x = WhereNode.__new__(WhereNode)
     36        memo[id(self)] = x
     37        for n, v in self.__dict__.iteritems():
     38            if n != 'connection':
     39                setattr(x, n, deepcopy(v, memo))
     40            else:
     41                setattr(x, n, self.connection)
     42        return x
     43
    2944    def as_sql(self, node=None, qn=None):
    3045        """
    3146        Returns the SQL version of the where clause and the value to be
     
    3853        if node is None:
    3954            node = self
    4055        if not qn:
    41             qn = connection.ops.quote_name
     56            qn = self.connection.ops.quote_name
    4257        if not node.children:
    4358            return None, []
    4459        result = []
     
    99114            lhs = '%s.%s' % (qn(table_alias), qn(name))
    100115        else:
    101116            lhs = qn(name)
    102         db_type = field and field.db_type() or None
    103         field_sql = connection.ops.field_cast_sql(db_type) % lhs
    104117
     118        db_type = field and field.db_type(self.connection.connection_name) or None
     119        field_sql = self.connection.ops.field_cast_sql(db_type) % lhs
     120       
    105121        if isinstance(value, datetime.datetime):
    106             cast_sql = connection.ops.datetime_cast_sql()
     122            cast_sql = self.connection.ops.datetime_cast_sql()
    107123        else:
    108124            cast_sql = '%s'
    109125
     
    116132        else:
    117133            extra = ''
    118134
    119         if lookup_type in connection.operators:
    120             format = "%s %%s %s" % (connection.ops.lookup_cast(lookup_type),
     135        if lookup_type in self.connection.operators:
     136            format = "%s %%s %s" % (self.connection.ops.lookup_cast(lookup_type),
    121137                    extra)
    122138            return (format % (field_sql,
    123                     connection.operators[lookup_type] % cast_sql), params)
     139                    self.connection.operators[lookup_type] % cast_sql), params)
    124140
    125141        if lookup_type == 'in':
    126142            if not value:
     
    132148        elif lookup_type in ('range', 'year'):
    133149            return ('%s BETWEEN %%s and %%s' % field_sql, params)
    134150        elif lookup_type in ('month', 'day'):
    135             return ('%s = %%s' % connection.ops.date_extract_sql(lookup_type,
     151            return ('%s = %%s' % self.connection.ops.date_extract_sql(lookup_type,
    136152                    field_sql), params)
    137153        elif lookup_type == 'isnull':
    138154            return ('%s IS %sNULL' % (field_sql, (not value and 'NOT ' or '')),
    139155                    params)
    140156        elif lookup_type == 'search':
    141             return (connection.ops.fulltext_search_sql(field_sql), params)
     157            return (self.connection.ops.fulltext_search_sql(field_sql), params)
    142158        elif lookup_type in ('regex', 'iregex'):
    143             return connection.ops.regex_lookup(lookup_type) % (field_sql, cast_sql), params
     159            return self.connection.ops.regex_lookup(lookup_type) % (field_sql, cast_sql), params
    144160
    145161        raise TypeError('Invalid lookup_type: %r' % lookup_type)
    146162
  • django/db/models/sql/query.py

     
    6060        # SQL-related attributes
    6161        self.select = []
    6262        self.tables = []    # Aliases in the order they are created.
    63         self.where = where()
     63        self.where = where(self.connection)
    6464        self.where_class = where
    6565        self.group_by = []
    6666        self.having = []
     
    215215        obj.related_select_cols = []
    216216        obj.related_select_fields = []
    217217        if obj.distinct and len(obj.select) > 1:
    218             obj = self.clone(CountQuery, _query=obj, where=self.where_class(),
     218            obj = self.clone(CountQuery, _query=obj, where=self.where_class(self.connection),
    219219                    distinct=False)
    220220            obj.select = []
    221221            obj.extra_select = {}
     
    346346                self.where.add(EverythingNode(), AND)
    347347        elif self.where:
    348348            # rhs has an empty where clause.
    349             w = self.where_class()
     349            w = self.where_class(self.connection)
    350350            w.add(EverythingNode(), AND)
    351351        else:
    352             w = self.where_class()
     352            w = self.where_class(self.connection)
    353353        self.where.add(w, connector)
    354354
    355355        # Selection columns and extra extensions are those provided by 'rhs'.
  • django/db/models/sql/subqueries.py

     
    4747        for related in cls._meta.get_all_related_many_to_many_objects():
    4848            if not isinstance(related.field, generic.GenericRelation):
    4949                for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
    50                     where = self.where_class()
     50                    where = self.where_class(self.connection)
    5151                    where.add((None, related.field.m2m_reverse_name(),
    5252                            related.field, 'in',
    5353                            pk_list[offset : offset+GET_ITERATOR_CHUNK_SIZE]),
     
    5555                    self.do_query(related.field.m2m_db_table(), where)
    5656
    5757        for f in cls._meta.many_to_many:
    58             w1 = self.where_class()
     58            w1 = self.where_class(self.connection)
    5959            if isinstance(f, generic.GenericRelation):
    6060                from django.contrib.contenttypes.models import ContentType
    6161                field = f.rel.to._meta.get_field(f.content_type_field_name)
    6262                w1.add((None, field.column, field, 'exact',
    6363                        ContentType.objects.get_for_model(cls).id), AND)
    6464            for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
    65                 where = self.where_class()
     65                where = self.where_class(self.connection)
    6666                where.add((None, f.m2m_column_name(), f, 'in',
    6767                        pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]),
    6868                        AND)
     
    7979        lot of values in pk_list.
    8080        """
    8181        for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
    82             where = self.where_class()
     82            where = self.where_class(self.connection)
    8383            field = self.model._meta.pk
    8484            where.add((None, field.column, field, 'in',
    8585                    pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), AND)
     
    178178
    179179        # Now we adjust the current query: reset the where clause and get rid
    180180        # of all the tables we don't need (since they're in the sub-select).
    181         self.where = self.where_class()
     181        self.where = self.where_class(self.connection)
    182182        if self.related_updates or must_pre_select:
    183183            # Either we're using the idents in multiple update queries (so
    184184            # don't want them to change), or the db backend doesn't support
     
    202202        This is used by the QuerySet.delete_objects() method.
    203203        """
    204204        for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
    205             self.where = self.where_class()
     205            self.where = self.where_class(self.connection)
    206206            f = self.model._meta.pk
    207207            self.where.add((None, f.column, f, 'in',
    208208                    pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]),
  • django/db/models/options.py

     
    5353        self.module_name = self.object_name.lower()
    5454        self.verbose_name = get_verbose_name(self.object_name)
    5555
     56        self.model = cls
     57
    5658        # Next, apply any overridden values from 'class Meta'.
    5759        if self.meta:
    5860            meta_attrs = self.meta.__dict__.copy()
     
    8486        del self.meta
    8587
    8688    def _prepare(self, model):
    87         from django.db import connection
    8889        from django.db.backends.util import truncate_name
     90        from django.db import connections, connection_name_app_model
    8991        if self.order_with_respect_to:
    9092            self.order_with_respect_to = self.get_field(self.order_with_respect_to)
    9193            self.ordering = ('_order',)
     
    107109        # If the db_table wasn't provided, use the app_label + module_name.
    108110        if not self.db_table:
    109111            self.db_table = "%s_%s" % (self.app_label, self.module_name)
    110             self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
     112            connection_name = connection_name_app_model(self.app_label, self.object_name)
     113            self.db_table = truncate_name(self.db_table, connections[connection_name].connection.ops.max_name_length())
    111114
    112115    def add_field(self, field):
    113116        # Insert the given field in the order in which it was created, using
  • django/db/models/fields/__init__.py

     
    77except ImportError:
    88    from django.utils import _decimal as decimal    # for Python 2.3
    99
    10 from django.db import get_creation_module
     10from django.db import connections
    1111from django.db.models import signals
    1212from django.db.models.query_utils import QueryWrapper
    1313from django.dispatch import dispatcher
     
    144144        """
    145145        return value
    146146
    147     def db_type(self):
     147    def db_type(self, connection):
    148148        """
    149149        Returns the database column data type for this field, taking into
    150150        account the DATABASE_ENGINE setting.
     
    165165        # can implement db_type() instead of get_internal_type() to specify
    166166        # exactly which wacky database column type you want to use.
    167167        try:
    168             return get_creation_module().DATA_TYPES[self.get_internal_type()] % self.__dict__
     168            return connections[connection].get_creation_module().DATA_TYPES[self.get_internal_type()] % self.__dict__
    169169        except KeyError:
    170170            return None
    171171
  • django/db/models/fields/related.py

     
    1 from django.db import connection, transaction
     1from django.db import transaction
    22from django.db.models import signals, get_model
    33from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class
    44from django.db.models.related import RelatedObject
     
    368368            # target_col_name: the PK colname in join_table for the target object
    369369            # *objs - objects to add. Either object instances, or primary keys of object instances.
    370370
     371            connection = self.model._default_manager.db.connection
     372
    371373            # If there aren't any objects, there is nothing to do.
    372374            if objs:
    373375                # Check that all the objects are of the right type
     
    391393                    cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
    392394                        (self.join_table, source_col_name, target_col_name),
    393395                        [self._pk_val, obj_id])
    394                 transaction.commit_unless_managed()
     396                transaction.commit_unless_managed(connection)
    395397
    396398        def _remove_items(self, source_col_name, target_col_name, *objs):
    397399            # source_col_name: the PK colname in join_table for the source object
    398400            # target_col_name: the PK colname in join_table for the target object
    399401            # *objs - objects to remove
    400402
     403            connection = self.model._default_manager.db.connection
     404
    401405            # If there aren't any objects, there is nothing to do.
    402406            if objs:
    403407                # Check that all the objects are of the right type
     
    413417                    (self.join_table, source_col_name,
    414418                    target_col_name, ",".join(['%s'] * len(old_ids))),
    415419                    [self._pk_val] + list(old_ids))
    416                 transaction.commit_unless_managed()
     420                transaction.commit_unless_managed(connection)
    417421
    418422        def _clear_items(self, source_col_name):
    419423            # source_col_name: the PK colname in join_table for the source object
     424            connection = self.model._default_manager.db.connection
    420425            cursor = connection.cursor()
    421426            cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
    422427                (self.join_table, source_col_name),
    423428                [self._pk_val])
    424             transaction.commit_unless_managed()
     429            transaction.commit_unless_managed(connection)
    425430
    426431    return ManyRelatedManager
    427432
     
    445450        superclass = rel_model._default_manager.__class__
    446451        RelatedManager = create_many_related_manager(superclass)
    447452
    448         qn = connection.ops.quote_name
     453        qn = rel_model._default_manager.db.connection.ops.quote_name
    449454        manager = RelatedManager(
    450455            model=rel_model,
    451456            core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()},
     
    486491        superclass = rel_model._default_manager.__class__
    487492        RelatedManager = create_many_related_manager(superclass)
    488493
    489         qn = connection.ops.quote_name
     494        qn = rel_model._default_manager.db.connection.ops.quote_name
    490495        manager = RelatedManager(
    491496            model=rel_model,
    492497            core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()},
     
    673678        defaults.update(kwargs)
    674679        return super(ForeignKey, self).formfield(**defaults)
    675680
    676     def db_type(self):
     681    def db_type(self, connection):
    677682        # The database column type of a ForeignKey is the column type
    678683        # of the field to which it points. An exception is if the ForeignKey
    679684        # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
    680685        # in which case the column type is simply that of an IntegerField.
    681686        rel_field = self.rel.get_related_field()
    682687        if isinstance(rel_field, (AutoField, PositiveIntegerField, PositiveSmallIntegerField)):
    683             return IntegerField().db_type()
    684         return rel_field.db_type()
     688            return IntegerField().db_type(connection)
     689        return rel_field.db_type(connection)
    685690
    686691class OneToOneField(ForeignKey):
    687692    """
     
    828833            defaults['initial'] = [i._get_pk_val() for i in defaults['initial']]
    829834        return super(ManyToManyField, self).formfield(**defaults)
    830835
    831     def db_type(self):
     836    def db_type(self, connection):
    832837        # A ManyToManyField is not represented by a single column,
    833838        # so return None.
    834839        return None
  • django/db/models/base.py

     
    1212from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField
    1313from django.db.models.query import delete_objects, Q
    1414from django.db.models.options import Options, AdminOptions
    15 from django.db import connection, transaction
     15from django.db import transaction
    1616from django.db.models import signals
    1717from django.db.models.loading import register_models, get_model
    1818from django.dispatch import dispatcher
     
    329329                result = manager._insert(values, return_id=update_pk)
    330330            else:
    331331                # Create a new record with defaults for everything.
    332                 result = manager._insert([(meta.pk, connection.ops.pk_default_value())], return_id=update_pk, raw_values=True)
     332                result = manager._insert([(meta.pk, manager.db.connection.ops.pk_default_value())], return_id=update_pk, raw_values=True)
    333333
    334334            if update_pk:
    335335                setattr(self, meta.pk.attname, result)
     
    419419    def _get_next_or_previous_in_order(self, is_next):
    420420        cachename = "__%s_order_cache" % is_next
    421421        if not hasattr(self, cachename):
    422             qn = connection.ops.quote_name
     422            qn = self._default_manager.db.connection.ops.quote_name
    423423            op = is_next and '>' or '<'
    424424            order = not is_next and '-_order' or '_order'
    425425            order_field = self._meta.order_with_respect_to
  • django/db/models/manager.py

     
    11import copy
    22
    33from django.db.models.query import QuerySet, EmptyQuerySet, insert_query
     4from django.db import ConnectionInfoDescriptor
    45from django.dispatch import dispatcher
    5 from django.db.models import signals
     6from django.db.models import signals, get_apps, get_models
    67from django.db.models.fields import FieldDoesNotExist
    78
    89def ensure_default_manager(sender):
     
    2223    # Tracks each time a Manager instance is created. Used to retain order.
    2324    creation_counter = 0
    2425
     26    db = ConnectionInfoDescriptor()
     27
    2528    def __init__(self):
    2629        super(Manager, self).__init__()
    2730        # Increase the creation counter, and save our local copy.
  • django/db/models/__init__.py

     
    11from django.conf import settings
    22from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
    33from django.core import validators
    4 from django.db import connection
    54from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models
    65from django.db.models.query import Q
    76from django.db.models.manager import Manager
  • django/db/models/query.py

     
    11import warnings
    22
    33from django.conf import settings
    4 from django.db import connection, transaction, IntegrityError
     4from django.db import transaction, IntegrityError
    55from django.db.models.fields import DateField, FieldDoesNotExist
    66from django.db.models.query_utils import Q
    77from django.db.models import signals, sql
     
    2020    "Represents a lazy database lookup for a set of objects"
    2121    def __init__(self, model=None, query=None):
    2222        self.model = model
    23         self.query = query or sql.Query(self.model, connection)
     23        self.query = query or sql.Query(self.model, self.model._default_manager.db.connection)
    2424        self._result_cache = None
    2525        self._iter = None
    2626
     
    689689                    instance=instance)
    690690
    691691        pk_list = [pk for pk,instance in seen_objs[cls]]
    692         del_query = sql.DeleteQuery(cls, connection)
     692        del_query = sql.DeleteQuery(cls, cls._default_manager.db.connection)
    693693        del_query.delete_batch_related(pk_list)
    694694
    695         update_query = sql.UpdateQuery(cls, connection)
     695        update_query = sql.UpdateQuery(cls, cls._default_manager.db.connection)
    696696        for field in cls._meta.fields:
    697697            if field.rel and field.null and field.rel.to in seen_objs:
    698698                update_query.clear_related(field, pk_list)
     
    701701    for cls in ordered_classes:
    702702        seen_objs[cls].reverse()
    703703        pk_list = [pk for pk,instance in seen_objs[cls]]
    704         del_query = sql.DeleteQuery(cls, connection)
     704        del_query = sql.DeleteQuery(cls, cls._default_manager.db.connection)
    705705        del_query.delete_batch(pk_list)
    706706
    707707        # Last cleanup; set NULLs where there once was a reference to the
     
    724724    the InsertQuery class and is how Model.save() is implemented. It is not
    725725    part of the public API.
    726726    """
    727     query = sql.InsertQuery(model, connection)
     727    query = sql.InsertQuery(model, model._default_manager.db.connection)
    728728    query.insert_values(values, raw_values)
    729729    return query.execute_sql(return_id)
    730730
  • django/db/__init__.py

     
    11import os
    2 from django.conf import settings
     2from django.conf import settings, UserSettingsHolder
    33from django.core import signals
    44from django.core.exceptions import ImproperlyConfigured
    55from django.dispatch import dispatcher
    66from django.utils.functional import curry
    77
     8try:
     9    # Only exists in Python 2.4+
     10    from threading import local
     11except ImportError:
     12    # Import copy of _thread_local.py from Python 2.4
     13    from django.utils._threading_local import local
     14
    815__all__ = ('backend', 'connection', 'DatabaseError', 'IntegrityError')
    916
     17
     18# singleton to represent the default connection in connections
     19class dummy(object):
     20    def __repr__(self):
     21        return self.__str__()
     22    def __str__(self):
     23        return '<default>'
     24_default = dummy()
     25del dummy
     26
     27
     28# storage for local default connection
     29_local = local()
     30
    1031if not settings.DATABASE_ENGINE:
    1132    settings.DATABASE_ENGINE = 'dummy'
    1233
    13 try:
    14     # Most of the time, the database backend will be one of the official
    15     # backends that ships with Django, so look there first.
    16     _import_path = 'django.db.backends.'
    17     backend = __import__('%s%s.base' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])
    18     creation = __import__('%s%s.creation' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])
    19 except ImportError, e:
    20     # If the import failed, we might be looking for a database backend
    21     # distributed external to Django. So we'll try that next.
    22     try:
    23         _import_path = ''
    24         backend = __import__('%s.base' % settings.DATABASE_ENGINE, {}, {}, [''])
    25         creation = __import__('%s.creation' % settings.DATABASE_ENGINE, {}, {}, [''])
    26     except ImportError, e_user:
    27         # The database backend wasn't found. Display a helpful error message
    28         # listing all possible (built-in) database backends.
    29         backend_dir = os.path.join(__path__[0], 'backends')
    30         available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')]
    31         available_backends.sort()
    32         if settings.DATABASE_ENGINE not in available_backends:
    33             raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s" % \
    34                 (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends)))
     34
     35def connect(settings, name, **kw):
     36    """Connect to the database specified in settings. Returns a
     37    ConnectionInfo on success, raises ImproperlyConfigured if the
     38    settings don't specify a valid database connection.
     39    """
     40    return ConnectionInfo(settings, name, **kw)
     41
     42
     43class ConnectionInfo(object):
     44    """Encapsulates all information about a connection and the backend
     45    to which it belongs. Provides methods for loading backend
     46    creation, introspection, and shell modules, closing the
     47    connection, and resetting the connection's query log.
     48    """
     49    def __init__(self, settings=None, name=_default, **kw):
     50        super(ConnectionInfo, self).__init__(**kw)
     51        if settings is None:
     52            from django.conf import settings
     53        if not settings.DATABASE_OPTIONS:
     54            settings.DATABASE_OPTIONS = {}
     55        self.settings = settings
     56        self.name = name
     57        self.backend = self.load_backend()
     58        self.connection = self.backend.DatabaseWrapper(settings, name)
     59        self.DatabaseError = self.backend.DatabaseError
     60
     61        # Register an event that closes the database connection
     62        # when a Django request is finished.
     63        dispatcher.connect(self.close, signal=signals.request_finished)
     64
     65        # Register an event that resets connection.queries
     66        # when a Django request is started.
     67        dispatcher.connect(self.reset_queries, signal=signals.request_started)
     68
     69    def __repr__(self):
     70        return "Connection: %s, %r (ENGINE=%s NAME=%s)" \
     71               % (self.name, self.connection,
     72                  self.settings.DATABASE_ENGINE,
     73                  self.settings.DATABASE_NAME)
     74
     75    def name(self):
     76        return self.name
     77
     78    def close(self):
     79        """Close connection"""
     80        self.connection.close()
     81
     82    def _import_database_module(self, import_path='', module_name=''):
     83        """Lazily import a database module when requested."""
     84        return __import__('%s%s.%s' % (import_path, self.settings.DATABASE_ENGINE, module_name), {}, {}, [''])
     85
     86    # We don't want to import the introspect module unless someone asks for it, so
     87    # lazily load it on demmand.
     88    def get_introspection_module(self):
     89        return self._import_database_module(self._import_path, 'introspection')
     90
     91    def get_creation_module(self):
     92        return self._import_database_module(self._import_path, 'creation')
     93
     94    def load_backend(self):
     95        try:
     96            # Most of the time, the database backend will be one of the official
     97            # backends that ships with Django, so look there first.
     98            self._import_path = 'django.db.backends.'
     99            backend = __import__('%s%s.base' % (self._import_path,
     100                            self.settings.DATABASE_ENGINE), {}, {}, [''])
     101        except ImportError, e:
     102            # If the import failed, we might be looking for a database backend
     103            # distributed external to Django. So we'll try that next.
     104            try:
     105                _import_path = ''
     106                backend = __import__('%s.base' % self.settings.DATABASE_ENGINE, {}, {}, [''])
     107            except ImportError, e_user:
     108                # The database backend wasn't found. Display a helpful error message
     109                # listing all possible (built-in) database backends.
     110                backend_dir = os.path.join(__path__[0], 'backends')
     111                available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')]
     112                available_backends.sort()
     113                if self.settings.DATABASE_ENGINE not in available_backends:
     114                    raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s" % \
     115                        (self.settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends)))
     116                else:
     117                    raise # If there's some other error, this must be an error in Django itself.
     118        return backend
     119
     120    # We want runshell() to work the same way, but we have to treat it a
     121    # little differently (since it just runs instead of returning a module like
     122    # the above) and wrap the lazily-loaded runshell() method.
     123    def runshell(self):
     124        return lambda: _import_database_module(_import_path, "client").runshell()
     125
     126    def reset_queries(self):
     127        """Reset log of queries executed by connection"""
     128        self.connection.queries = []
     129
     130class LazyConnectionManager(object):
     131    """Manages named connections lazily, instantiating them as
     132    they are requested.
     133    """
     134    def __init__(self):
     135        self.local = local()
     136        self.local.connections = {}
     137
     138        # Reset connections on request finish, to make sure each request can
     139        # load the correct connections for its settings
     140        dispatcher.connect(self.reset, signal=signals.request_finished)
     141
     142    def __iter__(self):
     143        # Iterates only over *active* connections, not all possible
     144        # connections
     145        return iter(self.local.connections.keys())
     146
     147    def __getattr__(self, attr):
     148        return getattr(self.local.connections, attr)
     149
     150    def __getitem__(self, k):
     151        try:
     152            return self.local.connections[k]
     153        except (AttributeError, KeyError):
     154            return self.connect(k)
     155
     156    def __setitem__(self, k, v):
     157        try:
     158            self.local.connections[k] = v
     159        except AttributeError:
     160            # First access in thread
     161            self.local.connections = {k: v}
     162
     163    def connect(self, name):
     164        """Return the connection with this name in
     165        settings.OTHER_DATABASES. Creates the connection if it doesn't yet
     166        exist. Reconnects if it does. If the name requested is the default
     167        connection (a singleton defined in django.db), then the default
     168        connection is returned.
     169        """
     170        try:
     171            cnx = self.local.connections
     172        except AttributeError:
     173            cnx = self.local.connections = {}
     174        if name in cnx:
     175            cnx[name].close()
     176        if name is _default:
     177            cnx[name] = connect(settings, _default)
     178            return cnx[name]
     179        try:
     180            info = settings.OTHER_DATABASES[name]
     181        except KeyError:
     182            raise ImproperlyConfigured, \
     183                  "No database connection '%s' has been configured" % name
     184        except AttributeError:
     185            raise ImproperlyConfigured, \
     186                  "No OTHER_DATABASES in settings."
     187
     188        # In settings it's a dict, but connect() needs an object:
     189        # pass global settings so that the default connection settings
     190        # can be defaults for the named connections.
     191        database = UserSettingsHolder(settings)
     192        for k, v in info.items():
     193            setattr(database, k, v)
     194        cnx[name] = connect(database, name)
     195        return cnx[name]
     196
     197    def items(self):
     198        # Iterates over *all possible* connections
     199        items = []
     200        for key in self.keys():
     201            items.append((key, self[key]))
     202        return items
     203
     204    def keys(self):
     205        # Iterates over *all possible* connections
     206        keys = [_default]
     207        try:
     208            keys.extend(settings.OTHER_DATABASES.keys())
     209        except AttributeError:
     210            pass
     211        return keys
     212
     213    def reset(self):
     214        if not hasattr(self.local, 'connections'):
     215            return
     216        if settings.DATABASE_NAME == ':memory:':
     217##            try:
     218##                cnx = self.local.connections
     219##            except AttributeError:
     220##                cnx = self.local.connections = {}
     221            self.local.connections = {_default: self.local.connections[_default]}
     222##            for c in cnx:
     223##                if c != _default:
     224##                    del self.local.connections[c]
    35225        else:
    36             raise # If there's some other error, this must be an error in Django itself.
     226            self.local.connections = {}
    37227
    38 def _import_database_module(import_path='', module_name=''):
    39     """Lazily import a database module when requested."""
    40     return __import__('%s%s.%s' % (import_path, settings.DATABASE_ENGINE, module_name), {}, {}, [''])
     228def model_connection_name(klass):
     229    """Get the connection name that a model is configured to use, with the
     230    current settings.
     231    """
     232    app = klass._meta.app_label
     233    model = klass.__name__
     234    app_model = "%s.%s" % (app, model)
    41235
    42 # We don't want to import the introspect module unless someone asks for it, so
    43 # lazily load it on demmand.
    44 get_introspection_module = curry(_import_database_module, _import_path, 'introspection')
     236    # Quick exit if no OTHER_DATABASES defined
     237    if (not hasattr(settings, 'OTHER_DATABASES')
     238        or not settings.OTHER_DATABASES):
     239        return _default
     240    # Look in MODELS for the best match: app_label.Model. If that isn't
     241    # found, take just app_label. If nothing is found, use the default
     242    maybe = None
     243    for name, db_def in settings.OTHER_DATABASES.items():
     244        if not 'MODELS' in db_def:
     245            continue
     246        mods = db_def['MODELS']
     247        # Can't get a better match than this
     248        if app_model in mods:
     249            return name
     250        elif app in mods:
     251            if maybe is not None:
     252                raise ImproperlyConfigured, \
     253                    "App %s appears in more than one OTHER_DATABASES " \
     254                    "setting (%s and %s)" % (maybe, name)
     255            maybe = name
     256    if maybe:
     257        return maybe
     258    # No named connection for this model; use the default
     259    return _default
    45260
    46 def get_creation_module():
    47     return creation
     261def connection_name_app_model(app_label, model_name):
     262    """Get the connection name that a model is configured to use, with the
     263    current settings.
     264    """
     265    app_model = "%s.%s" % (app_label, model_name)
    48266
    49 # We want runshell() to work the same way, but we have to treat it a
    50 # little differently (since it just runs instead of returning a module like
    51 # the above) and wrap the lazily-loaded runshell() method.
    52 runshell = lambda: _import_database_module(_import_path, "client").runshell()
     267    # Quick exit if no OTHER_DATABASES defined
     268    if (not hasattr(settings, 'OTHER_DATABASES')
     269        or not settings.OTHER_DATABASES):
     270        return _default
     271    # Look in MODELS for the best match: app_label.Model. If that isn't
     272    # found, take just app_label. If nothing is found, use the default
     273    maybe = None
     274    for name, db_def in settings.OTHER_DATABASES.items():
     275        if not 'MODELS' in db_def:
     276            continue
     277        mods = db_def['MODELS']
     278        # Can't get a better match than this
     279        if app_model in mods:
     280            return name
     281        elif app_label in mods:
     282            if maybe is not None:
     283                raise ImproperlyConfigured, \
     284                    "App %s appears in more than one OTHER_DATABASES " \
     285                    "setting (%s and %s)" % (maybe, name)
     286            maybe = name
     287    if maybe:
     288        return maybe
     289    # No named connection for this model; use the default
     290    return _default
    53291
    54 # Convenient aliases for backend bits.
    55 connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS)
    56 DatabaseError = backend.DatabaseError
    57 IntegrityError = backend.IntegrityError
     292class ConnectionInfoDescriptor(object):
     293    """Descriptor used to access database connection information from a
     294    manager or other connection holder. Keeps a thread-local cache of
     295    connections per instance, and always returns the same connection for an
     296    instance in particular thread during a particular request.
    58297
    59 # Register an event that closes the database connection
    60 # when a Django request is finished.
    61 dispatcher.connect(connection.close, signal=signals.request_finished)
     298    Any object that includes a ``model`` attribute that holds a model class
     299    can use this descriptor to manage connections.
     300    """
    62301
    63 # Register an event that resets connection.queries
    64 # when a Django request is started.
     302    def __init__(self):
     303        self.local = local()
     304        self.local.cnx = {}
     305        dispatcher.connect(self.reset, signal=signals.request_finished)
     306
     307    def __get__(self, instance, type=None):
     308        if instance is None:
     309            raise AttributeError, \
     310                "ConnectionInfo is accessible only through an instance"
     311        try:
     312            instance_connection = self.local.cnx.get(instance, None)
     313        except AttributeError:
     314            # First access in this thread
     315            self.local.cnx = {}
     316            instance_connection = None
     317        if instance_connection is None:
     318            instance_connection = self.get_connection(instance)
     319            self.local.cnx[instance] = instance_connection
     320        return instance_connection
     321
     322    def __set__(self, instance, value):
     323        try:
     324            self.local.cnx[instance] = value
     325        except AttributeError:
     326            # First access in thread
     327            self.local.cnx = {instance: value}
     328
     329    def __delete__(self, instance):
     330        try:
     331            del self.local.cnx[instance]
     332        except (AttributeError, KeyError):
     333            # Not stored, no need to reset
     334            pass
     335
     336    def get_connection(self, instance):
     337        return connections[model_connection_name(instance.model)]
     338
     339    def reset(self):
     340        if not hasattr(self.local, 'cnx'):
     341            return
     342        self.local.cnx = {}
     343
     344class LocalizingProxy:
     345    """A lazy-initializing proxy. The proxied object is not
     346    initialized until the first attempt to access it. This is used to
     347    attach module-level properties to local storage.
     348    """
     349    def __init__(self, name, storage, func, *arg, **kw):
     350        self.__name = name
     351        self.__storage = storage
     352        self.__func = func
     353        self.__arg = arg
     354        self.__kw = kw
     355
     356        # We need to clear out this thread's storage at the end of each
     357        # request, in case new settings are loaded with the next
     358        def reset(stor=storage, name=name):
     359            if hasattr(stor, name):
     360                delattr(stor, name)
     361        dispatcher.connect(reset, signal=signals.request_finished)
     362
     363    def __getattr__(self, attr):
     364        # Private (__*) attributes are munged
     365        if attr.startswith('_LocalizingProxy'):
     366            return self.__dict__[attr]
     367        try:
     368            return getattr(getattr(self.__storage, self.__name), attr)
     369        except AttributeError:
     370            setattr(self.__storage, self.__name, self.__func(*self.__arg,
     371                                                             **self.__kw))
     372            return getattr(getattr(self.__storage, self.__name), attr)
     373
     374    def __setattr__(self, attr, val):
     375        # Private (__*) attributes are munged
     376        if attr.startswith('_LocalizingProxy'):
     377            self.__dict__[attr] = val
     378            return
     379        try:
     380            stor = getattr(self.__storage, self.__name)
     381        except AttributeError:
     382            stor =  self.__func(*self.__arg)
     383            setattr(self.__storage, self.__name, stor)
     384        setattr(stor, attr, val)
     385
     386
     387# Create a manager for named connections
     388connections = LazyConnectionManager()
     389
     390# Backwards compatibility: establish the default connection and set the
     391# default connection properties at module level, using the lazy proxy so that
     392# each thread may have a different default connection, if so configured
     393connection_info = LocalizingProxy('connection_info', _local,
     394                                  lambda: connections[_default])
     395connection = LocalizingProxy('connection', _local,
     396                             lambda: connections[_default].connection)
     397backend = LocalizingProxy('backend', _local,
     398                          lambda: connections[_default].backend)
     399DatabaseError = LocalizingProxy('DatabaseError', _local,
     400                                lambda: connections[_default].DatabaseError)
     401IntegrityError = LocalizingProxy('IntegrityError', _local,
     402                                lambda: connections[_default].IntegrityError)
     403get_introspection_module = LocalizingProxy(
     404    'get_introspection_module', _local,
     405    lambda: connections[_default].get_introspection_module)
     406get_creation_module = LocalizingProxy(
     407    'get_creation_module', _local,
     408    lambda: connections[_default].get_creation_module)
     409runshell = LocalizingProxy('runshell', _local,
     410                           lambda: connections[_default].runshell)
     411
     412
    65413def reset_queries():
    66     connection.queries = []
    67 dispatcher.connect(reset_queries, signal=signals.request_started)
     414    connections[_default].reset_queries()
     415    for c in connections:
     416        try:
     417            c.reset_queries()
     418        except:
     419            pass
    68420
    69 # Register an event that rolls back the connection
     421# Register an event that rolls back all connections
    70422# when a Django request has an exception.
    71423def _rollback_on_exception():
    72424    from django.db import transaction
    73425    transaction.rollback_unless_managed()
    74 dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception)
     426dispatcher.connect(_rollback_on_exception,
     427                   signal=signals.got_request_exception)
     428
  • django/db/backends/__init__.py

     
    55    # Import copy of _thread_local.py from Python 2.4
    66    from django.utils._threading_local import local
    77
    8 class BaseDatabaseWrapper(local):
     8class BaseDatabaseWrapper(object):
    99    """
    1010    Represents a database connection.
    1111    """
    1212    ops = None
    13     def __init__(self, **kwargs):
     13    def __init__(self, settings, connection_name):
     14        self.settings = settings
     15        self.connection_name = connection_name
     16        self.options = settings.DATABASE_OPTIONS
    1417        self.connection = None
    1518        self.queries = []
    16         self.options = kwargs
    1719
    1820    def _commit(self):
    1921        if self.connection is not None:
     
    2931            self.connection = None
    3032
    3133    def cursor(self):
    32         from django.conf import settings
     34        settings = self.settings
    3335        cursor = self._cursor(settings)
    3436        if settings.DEBUG:
    3537            return self.make_debug_cursor(cursor)
  • django/db/backends/sqlite3/base.py

     
    118118        return self.connection.cursor(factory=SQLiteCursorWrapper)
    119119
    120120    def close(self):
    121         from django.conf import settings
     121        settings = self.settings
    122122        # If database is in memory, closing the connection destroys the
    123123        # database. To prevent accidental data loss, ignore close requests on
    124124        # an in-memory db.
  • django/db/transaction.py

     
    1616    import thread
    1717except ImportError:
    1818    import dummy_thread as thread
    19 from django.db import connection
    2019from django.conf import settings
    2120
    2221class TransactionManagementError(Exception):
     
    116115    Puts the transaction manager into a manual state: managed transactions have
    117116    to be committed explicitly by the user. If you switch off transaction
    118117    management and there is a pending commit/rollback, the data will be
    119     commited.
     118    commited. Note that managed state applies across all connections.
    120119    """
    121120    thread_ident = thread.get_ident()
    122121    top = state.get(thread_ident, None)
    123122    if top:
    124123        top[-1] = flag
    125124        if not flag and is_dirty():
    126             connection._commit()
     125            for cx in all_connections():
     126                cx._commit()
    127127            set_clean()
    128128    else:
    129129        raise TransactionManagementError("This code isn't under transaction management")
    130130
    131 def commit_unless_managed():
     131def commit_unless_managed(conns=None):
    132132    """
    133133    Commits changes if the system is not in managed transaction mode.
    134134    """
    135135    if not is_managed():
    136         connection._commit()
     136        if conns is None:
     137            conns = all_connections()
     138        else:
     139            conns = ensure_connections(conns)
     140        for cx in conns:
     141            cx._commit()
    137142    else:
    138143        set_dirty()
    139144
    140 def rollback_unless_managed():
     145def rollback_unless_managed(conns=None):
    141146    """
    142147    Rolls back changes if the system is not in managed transaction mode.
    143148    """
    144149    if not is_managed():
    145         connection._rollback()
     150        if conns is None:
     151            conns = all_connections()
     152        else:
     153            conns = ensure_connections(conns)
     154        for cx in conns:
     155            cx._rollback()
    146156    else:
    147157        set_dirty()
    148158
    149 def commit():
     159def commit(conns=None):
    150160    """
    151161    Does the commit itself and resets the dirty flag.
    152162    """
    153     connection._commit()
     163    if conns is None:
     164        conns = all_connections()
     165    else:
     166        conns = ensure_connections(conns)
     167    for cx in conns:
     168        cx._commit()
    154169    set_clean()
    155170
    156 def rollback():
     171def rollback(conns=None):
    157172    """
    158173    This function does the rollback itself and resets the dirty flag.
    159174    """
    160     connection._rollback()
     175    if conns is None:
     176        conns = all_connections()
     177    else:
     178        conns = ensure_connections(conns)
     179    for cx in conns:
     180        cx._rollback()
    161181    set_clean()
    162182
    163183##############
     
    179199            leave_transaction_management()
    180200    return _autocommit
    181201
    182 def commit_on_success(func):
     202def commit_on_success(func, conns = None):
    183203    """
    184204    This decorator activates commit on response. This way, if the view function
    185205    runs successfully, a commit is made; if the viewfunc produces an exception,
     
    198218                raise
    199219            else:
    200220                if is_dirty():
    201                     commit()
     221                    commit(conns)
    202222            return res
    203223        finally:
    204224            leave_transaction_management()
     
    220240            leave_transaction_management()
    221241
    222242    return _commit_manually
     243
     244###########
     245# HELPERS #
     246###########
     247
     248def all_connections():
     249    from django.db import connection, connections
     250    return [connection] + [ c.connection
     251                               for c in connections.values() ]
     252
     253def ensure_connections(val):
     254    from django.db import connections
     255    conns = []
     256    if isinstance(val, basestring):
     257        val = [val]
     258    try:
     259        iter(val)
     260    except:
     261        val = [val]
     262    for cx in val:
     263        if hasattr(cx, 'cursor'):
     264            conns.append(cx)
     265        elif hasattr(cx, 'connection'):
     266            conns.append(cx.connection)
     267        elif isinstance(cx, basestring):
     268            conns.append(connections[cx].connection)
     269    return conns
     270
  • django/core/context_processors.py

     
    3333    context_extras = {}
    3434    if settings.DEBUG and request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS:
    3535        context_extras['debug'] = True
    36         from django.db import connection
    37         context_extras['sql_queries'] = connection.queries
     36        from django.db import connections
     37        queries = []
     38        for conn in connections:
     39            queries.extend(connections[conn].connection.queries)
     40        context_extras['sql_queries'] = queries
    3841    return context_extras
    3942
    4043def i18n(request):
  • django/core/cache/backends/db.py

     
    11"Database cache backend."
    22
    33from django.core.cache.backends.base import BaseCache
    4 from django.db import connection, transaction, DatabaseError
     4from django.db import connections, _default, transaction, DatabaseError
    55import base64, time
    66from datetime import datetime
    77try:
     
    2525            self._cull_frequency = 3
    2626
    2727    def get(self, key, default=None):
    28         cursor = connection.cursor()
     28        cursor = connections[_default].connection.cursor()
    2929        cursor.execute("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % self._table, [key])
    3030        row = cursor.fetchone()
    3131        if row is None:
     
    4646    def _base_set(self, mode, key, value, timeout=None):
    4747        if timeout is None:
    4848            timeout = self.default_timeout
    49         cursor = connection.cursor()
     49        cursor = connections[_default].connection.cursor()
    5050        cursor.execute("SELECT COUNT(*) FROM %s" % self._table)
    5151        num = cursor.fetchone()[0]
    5252        now = datetime.now().replace(microsecond=0)
     
    6767            transaction.commit_unless_managed()
    6868
    6969    def delete(self, key):
    70         cursor = connection.cursor()
     70        cursor = connections[_default].connection.cursor()
    7171        cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % self._table, [key])
    7272        transaction.commit_unless_managed()
    7373
    7474    def has_key(self, key):
    75         cursor = connection.cursor()
     75        cursor = connections[_default].connection.cursor()
    7676        cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % self._table, [key])
    7777        return cursor.fetchone() is not None
    7878
  • django/core/management/commands/sqlall.py

     
    77
    88    def handle_app(self, app, **options):
    99        from django.core.management.sql import sql_all
    10         return '\n'.join(sql_all(app, self.style))
     10        return sql_all(app, self.style)
  • django/core/management/commands/sqlcustom.py

     
    77
    88    def handle_app(self, app, **options):
    99        from django.core.management.sql import sql_custom
    10         return '\n'.join(sql_custom(app))
     10        return sql_custom(app)
     11
  • django/core/management/commands/createcachetable.py

     
    88    requires_model_validation = False
    99
    1010    def handle_label(self, tablename, **options):
    11         from django.db import connection, transaction, models
     11        from django.db import connections, transaction, models, _default
    1212        fields = (
    1313            # "key" is a reserved word in MySQL, so use "cache_key" instead.
    1414            models.CharField(name='cache_key', max_length=255, unique=True, primary_key=True),
     
    1717        )
    1818        table_output = []
    1919        index_output = []
    20         qn = connection.ops.quote_name
     20        qn = connections[_default].connection.ops.quote_name
    2121        for f in fields:
    22             field_output = [qn(f.name), f.db_type()]
     22            field_output = [qn(f.name), f.db_type(_default)]
    2323            field_output.append("%sNULL" % (not f.null and "NOT " or ""))
    2424            if f.unique:
    2525                field_output.append("UNIQUE")
     
    3535        for i, line in enumerate(table_output):
    3636            full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
    3737        full_statement.append(');')
    38         curs = connection.cursor()
     38        curs = connection[_default].connection.cursor()
    3939        curs.execute("\n".join(full_statement))
    4040        for statement in index_output:
    4141            curs.execute(statement)
  • django/core/management/commands/sql.py

     
    77
    88    def handle_app(self, app, **options):
    99        from django.core.management.sql import sql_create
    10         return '\n'.join(sql_create(app, self.style))
     10        return sql_create(app, self.style)
  • django/core/management/commands/sqlflush.py

     
    1 from django.core.management.base import NoArgsCommand
     1from django.core.management.base import ConnectionCommand
    22
    3 class Command(NoArgsCommand):
     3class Command(ConnectionCommand):
    44    help = "Returns a list of the SQL statements required to return all tables in the database to the state they were in just after they were installed."
    55
    66    output_transaction = True
    77
    8     def handle_noargs(self, **options):
     8    def handle_connection(self, connection, **options):
    99        from django.core.management.sql import sql_flush
    10         return '\n'.join(sql_flush(self.style, only_django=True))
     10        return sql_flush(connection, self.style, only_django=True)
  • django/core/management/commands/sqlreset.py

     
    77
    88    def handle_app(self, app, **options):
    99        from django.core.management.sql import sql_reset
    10         return '\n'.join(sql_reset(app, self.style))
     10        return sql_reset(app, self.style)
  • django/core/management/commands/sqlclear.py

     
    77
    88    def handle_app(self, app, **options):
    99        from django.core.management.sql import sql_delete
    10         return '\n'.join(sql_delete(app, self.style))
     10        return sql_delete(app, self.style)
  • django/core/management/commands/loaddata.py

     
    2121    def handle(self, *fixture_labels, **options):
    2222        from django.db.models import get_apps
    2323        from django.core import serializers
    24         from django.db import connection, transaction
     24        from django.db import connections, model_connection_name, transaction
     25# MULTIDB: TO REMOVE
     26        from django.db import connection
    2527        from django.conf import settings
    2628
    2729        self.style = no_style()
     
    3941        # Get a cursor (even though we don't need one yet). This has
    4042        # the side effect of initializing the test database (if
    4143        # it isn't already initialized).
    42         cursor = connection.cursor()
     44##        cursor = connection.cursor()
    4345
    4446        # Start transaction management. All fixtures are installed in a
    4547        # single transaction to ensure that all references are resolved.
     
    121123                            print "No %s fixture '%s' in %s." % \
    122124                                (format, fixture_name, humanize(fixture_dir))
    123125
     126# MULTIDB TODO: use sql_sequence_reset
    124127        if object_count > 0:
    125128            sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
    126129            if sequence_sql:
  • django/core/management/commands/inspectdb.py

     
    1 from django.core.management.base import NoArgsCommand, CommandError
     1from django.core.management.base import ConnectionCommand, CommandError
    22
    3 class Command(NoArgsCommand):
     3class Command(ConnectionCommand):
    44    help = "Introspects the database tables in the given database and outputs a Django model module."
    55
    66    requires_model_validation = False
    77
    8     def handle_noargs(self, **options):
     8    def handle_connection(self, connection, **options):
    99        try:
    10             for line in self.handle_inspection():
     10            for line in self.handle_inspection(connection):
    1111                print line
    1212        except NotImplementedError:
    1313            raise CommandError("Database inspection isn't supported for the currently selected database backend.")
    1414
    15     def handle_inspection(self):
    16         from django.db import connection, get_introspection_module
     15    def handle_inspection(self, conn):
     16        from django.db import connections, get_introspection_module
    1717        import keyword
    1818
    19         introspection_module = get_introspection_module()
     19        connection = connections[conn].connection
     20        introspection_module = connections[conn].get_introspection_module()
    2021
    2122        table2model = lambda table_name: table_name.title().replace('_', '')
    2223
  • django/core/management/commands/sqlindexes.py

     
    77
    88    def handle_app(self, app, **options):
    99        from django.core.management.sql import sql_indexes
    10         return '\n'.join(sql_indexes(app, self.style))
     10        return sql_indexes(app, self.style)
  • django/core/management/commands/reset.py

     
    1010    help = "Executes ``sqlreset`` for the given app(s) in the current database."
    1111    args = '[appname ...]'
    1212
    13     output_transaction = True
    14 
    1513    def handle_app(self, app, **options):
    16         from django.db import connection, transaction
     14        from django.db import connections, transaction, _default
    1715        from django.conf import settings
    1816        from django.core.management.sql import sql_reset
    1917
     
    2119
    2220        self.style = no_style()
    2321
    24         sql_list = sql_reset(app, self.style)
     22        sql_dict = sql_reset(app, self.style)
    2523
    26         if options.get('interactive'):
    27             confirm = raw_input("""
     24        for connection_name, sql_list in sql_dict.items():
     25            if options.get('interactive'):
     26                if connection_name == _default:
     27                    dbname = settings.DATABASE_NAME
     28                else:
     29                    dbname = settings.OTHER_DATABASES[connection_name]['DATABASE_NAME']
     30                confirm = raw_input("""
    2831You have requested a database reset.
    2932This will IRREVERSIBLY DESTROY any data for
    3033the "%s" application in the database "%s".
    3134Are you sure you want to do this?
    3235
    33 Type 'yes' to continue, or 'no' to cancel: """ % (app_name, settings.DATABASE_NAME))
    34         else:
    35             confirm = 'yes'
     36Type 'yes' to continue, or 'no' to cancel: """ % (app_name, dbname))
     37            else:
     38                confirm = 'yes'
    3639
    37         if confirm == 'yes':
    38             try:
    39                 cursor = connection.cursor()
    40                 for sql in sql_list:
    41                     cursor.execute(sql)
    42             except Exception, e:
    43                 transaction.rollback_unless_managed()
    44                 raise CommandError("""Error: %s couldn't be reset. Possible reasons:
     40            if confirm == 'yes':
     41                try:
     42                    cursor = connections[connection_name].connection.cursor()
     43                    for sql in sql_list:
     44                        cursor.execute(sql)
     45                except Exception, e:
     46                    transaction.rollback_unless_managed()
     47                    raise CommandError("""Error: %s couldn't be reset. Possible reasons:
    4548  * The database isn't running or isn't configured correctly.
    4649  * At least one of the database tables doesn't exist.
    4750  * The SQL was invalid.
    4851Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run.
    4952The full error: %s""" % (app_name, app_name, e))
    50             transaction.commit_unless_managed()
    51         else:
    52             print "Reset cancelled."
     53                transaction.commit_unless_managed()
     54            else:
     55                print "Reset cancelled."
  • django/core/management/commands/syncdb.py

     
    1919    help = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
    2020
    2121    def handle_noargs(self, **options):
    22         from django.db import connection, transaction, models
     22        from django.db import model_connection_name, transaction, models, connections
    2323        from django.conf import settings
    2424        from django.core.management.sql import table_list, installed_models, sql_model_create, sql_for_pending_references, many_to_many_sql_for_model, custom_sql_for_model, sql_indexes_for_model, emit_post_sync_signal
    2525
     
    3737                if not exc.args[0].startswith('No module named management'):
    3838                    raise
    3939
    40         cursor = connection.cursor()
    41 
    42         if connection.features.uses_case_insensitive_names:
    43             table_name_converter = lambda x: x.upper()
    44         else:
    45             table_name_converter = lambda x: x
    4640        # Get a list of all existing database tables, so we know what needs to
    4741        # be added.
    48         tables = [table_name_converter(name) for name in table_list()]
    49 
     42        tables = table_list()
     43       
    5044        # Get a list of already installed *models* so that references work right.
    5145        seen_models = installed_models(tables)
    5246        created_models = set()
     
    5953            for model in model_list:
    6054                # Create the model's database table, if it doesn't already exist.
    6155                if verbosity >= 2:
    62                     print "Processing %s.%s model" % (app_name, model._meta.object_name)
    63                 if table_name_converter(model._meta.db_table) in tables:
     56                    print "Processing %s.%s model (%s))" % (app_name, model._meta.object_name, model_connection_name(model))
     57                connection = model._default_manager.db.connection
     58                cursor = connection.cursor()
     59                if connection.features.uses_case_insensitive_names:
     60                    table_name_converter = lambda x: x.upper()
     61                else:
     62                    table_name_converter = lambda x: x
     63                ctables = [table_name_converter(name) for name in tables]
     64                if table_name_converter(model._meta.db_table) in ctables:
    6465                    continue
    6566                sql, references = sql_model_create(model, self.style, seen_models)
    6667                seen_models.add(model)
     
    8384            model_list = models.get_models(app)
    8485            for model in model_list:
    8586                if model in created_models:
     87                    connection = model._default_manager.db.connection
     88                    cursor = connection.cursor()
    8689                    sql = many_to_many_sql_for_model(model, self.style)
    8790                    if sql:
    8891                        if verbosity >= 2:
     
    102105            app_name = app.__name__.split('.')[-2]
    103106            for model in models.get_models(app):
    104107                if model in created_models:
     108                    connection = model._default_manager.db.connection
     109                    cursor = connection.cursor()
    105110                    custom_sql = custom_sql_for_model(model)
    106111                    if custom_sql:
    107112                        if verbosity >= 1:
     
    121126            app_name = app.__name__.split('.')[-2]
    122127            for model in models.get_models(app):
    123128                if model in created_models:
     129                    connection = model._default_manager.db.connection
     130                    cursor = connection.cursor()
    124131                    index_sql = sql_indexes_for_model(model, self.style)
    125132                    if index_sql:
    126133                        if verbosity >= 1:
  • django/core/management/commands/flush.py

     
    1 from django.core.management.base import NoArgsCommand, CommandError
     1from django.core.management.base import ConnectionCommand, CommandError
    22from django.core.management.color import no_style
    33from optparse import make_option
    44
    5 class Command(NoArgsCommand):
    6     option_list = NoArgsCommand.option_list + (
     5class Command(ConnectionCommand):
     6    option_list = ConnectionCommand.option_list + (
    77        make_option('--verbosity', action='store', dest='verbosity', default='1',
    88            type='choice', choices=['0', '1', '2'],
    99            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
     
    1212    )
    1313    help = "Executes ``sqlflush`` on the current database."
    1414
    15     def handle_noargs(self, **options):
     15    def handle_connection(self, connection, **options):
    1616        from django.conf import settings
    17         from django.db import connection, transaction, models
     17        from django.db import transaction, models, connections
    1818        from django.dispatch import dispatcher
    1919        from django.core.management.sql import sql_flush, emit_post_sync_signal
    2020
     
    3131            except ImportError:
    3232                pass
    3333
    34         sql_list = sql_flush(self.style, only_django=True)
     34        sql_list = sql_flush(connection, self.style, only_django=True)
    3535
    3636        if interactive:
    3737            confirm = raw_input("""You have requested a flush of the database.
     
    3939and return each table to the state it was in after syncdb.
    4040Are you sure you want to do this?
    4141
    42     Type 'yes' to continue, or 'no' to cancel: """ % settings.DATABASE_NAME)
     42    Type 'yes' to continue, or 'no' to cancel: """ % connection)
    4343        else:
    4444            confirm = 'yes'
    4545
    4646        if confirm == 'yes':
    4747            try:
    48                 cursor = connection.cursor()
    4948                for sql in sql_list:
     49                    cursor = connections[connection].connection.cursor()
    5050                    cursor.execute(sql)
    5151            except Exception, e:
    5252                transaction.rollback_unless_managed()
     
    5555      * At least one of the expected database tables doesn't exist.
    5656      * The SQL was invalid.
    5757    Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.
    58     The full error: %s""" % (settings.DATABASE_NAME, e))
     58    The full error: %s""" % (connection, e))
    5959            transaction.commit_unless_managed()
    6060
    6161            # Emit the post sync signal. This allows individual
  • django/core/management/base.py

     
    8585                self.validate()
    8686            output = self.handle(*args, **options)
    8787            if output:
    88                 if self.output_transaction:
    89                     # This needs to be imported here, because it relies on settings.
    90                     from django.db import connection
    91                     if connection.ops.start_transaction_sql():
    92                         print self.style.SQL_KEYWORD(connection.ops.start_transaction_sql())
    9388                print output
    94                 if self.output_transaction:
    95                     print self.style.SQL_KEYWORD("COMMIT;")
    9689        except CommandError, e:
    9790            sys.stderr.write(self.style.ERROR(str('Error: %s\n' % e)))
    9891            sys.exit(1)
     
    124117    args = '<appname appname ...>'
    125118
    126119    def handle(self, *app_labels, **options):
    127         from django.db import models
     120        from django.db import models, _default, connections
     121        from django.core.management.sql import sql_collate
    128122        if not app_labels:
    129123            raise CommandError('Enter at least one appname.')
    130124        try:
    131125            app_list = [models.get_app(app_label) for app_label in app_labels]
    132126        except (ImproperlyConfigured, ImportError), e:
    133127            raise CommandError("%s. Are you sure your INSTALLED_APPS setting is correct?" % e)
    134         output = []
     128        output = {}
    135129        for app in app_list:
    136130            app_output = self.handle_app(app, **options)
    137             if app_output:
    138                 output.append(app_output)
    139         return '\n'.join(output)
     131            if isinstance(app_output, dict):
     132                for connection_name, statements in app_output.items():
     133                    f_output = output.setdefault(connection_name, [])
     134                    if self.output_transaction:
     135                        if connections[connection_name].connection.ops.start_transaction_sql():
     136                            f_output.append(self.style.SQL_KEYWORD(connections[connection_name].connection.ops.start_transaction_sql()))
     137                    f_output.extend(statements)
     138                    if self.output_transaction:
     139                        f_output.append(self.style.SQL_KEYWORD("COMMIT;"))
     140            else:
     141                f_output = output.setdefault(_default, [])
     142                f_output.append(app_output)
    140143
     144        return sql_collate(output)
     145##        return '\n'.join(output)
     146
    141147    def handle_app(self, app, **options):
    142148        raise NotImplementedError()
    143149
     150class ConnectionCommand(BaseCommand):
     151    args = '<connectionname connectionname ...>'
     152
     153    def handle(self, *connection_labels, **options):
     154        from django.conf import settings
     155        from django.db import _default, connections
     156        from django.core.management.sql import sql_collate
     157        if not connection_labels:
     158            connection_list = [_default]
     159            connection_list.extend(settings.OTHER_DATABASES.keys())
     160        else:
     161            # add check connection exists
     162            connection_list = []
     163            for name in connection_labels:
     164                if name == '_default':
     165                    connection_list.append(_default)
     166                elif name in settings.OTHER_DATABASES:
     167                    connection_list.append(name)
     168        output = {}
     169        for connection_name in connection_list:
     170            f_output = output.setdefault(connection_name, [])
     171            connection_output = self.handle_connection(connection_name, **options)
     172            if connection_output:
     173                if self.output_transaction:
     174                    if connections[connection_name].connection.ops.start_transaction_sql():
     175                        f_output.append(self.style.SQL_KEYWORD(connections[connection_name].connection.ops.start_transaction_sql()))
     176                f_output.extend(connection_output)
     177                if self.output_transaction:
     178                    f_output.append(self.style.SQL_KEYWORD("COMMIT;"))
     179        return sql_collate(output)
     180
     181    def handle_connection(self, connection_name, **options):
     182        raise NotImplementedError()
     183
    144184class LabelCommand(BaseCommand):
    145185    args = '<label label ...>'
    146186    label = 'label'
  • django/core/management/sql.py

     
    88    from sets import Set as set   # Python 2.3 fallback
    99
    1010def table_list():
    11     "Returns a list of all table names that exist in the database."
    12     from django.db import connection, get_introspection_module
    13     cursor = connection.cursor()
    14     return get_introspection_module().get_table_list(cursor)
     11    """Returns a list of all table names that exist in the database."""
     12    from django.db import connections
     13    table_list = []
     14    for conn in connections:
     15        table_list.extend(table_list_conn(conn))
     16    return table_list
    1517
     18def table_list_conn(conn):
     19    from django.db import connections
     20    try:
     21        cursor = connections[conn].connection.cursor()
     22        return connections[conn].get_introspection_module().get_table_list(cursor)
     23    except:
     24        return []
     25
    1626def django_table_list(only_existing=False):
    1727    """
    1828    Returns a list of all table names that have associated Django models and
     
    3242        tables = [t for t in tables if t in existing]
    3343    return tables
    3444
     45def django_table_list_conn(conn, only_existing=False):
     46    from django.db import models
     47    from django.db import model_connection_name
     48    tables = []
     49    for app in models.get_apps():
     50        for model in models.get_models(app):
     51            if model_connection_name(model)==conn:
     52                tables.append(model._meta.db_table)
     53                tables.extend([f.m2m_db_table() for f in model._meta.many_to_many])
     54    if only_existing:
     55        existing = table_list_conn(conn)
     56        tables = [t for t in tables if t in existing]
     57    return tables
     58
    3559def installed_models(table_list):
    3660    "Returns a set of all models that are installed, given a list of existing table names."
    37     from django.db import connection, models
     61    from django.db import models
    3862    all_models = []
    3963    for app in models.get_apps():
    4064        for model in models.get_models(app):
    41             all_models.append(model)
    42     if connection.features.uses_case_insensitive_names:
    43         converter = lambda x: x.upper()
    44     else:
    45         converter = lambda x: x
    46     return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
     65            connection = model._default_manager.db.connection
     66            if connection.features.uses_case_insensitive_names:
     67                converter = lambda x: x.upper()
     68            else:
     69                converter = lambda x: x
     70            if converter(model._meta.db_table) in map(converter, table_list):
     71                all_models.append(converter(model))
     72    return set(all_models)
    4773
    4874def sequence_list():
    4975    "Returns a list of information about all DB sequences for all models in all apps."
     
    6692
    6793def sql_create(app, style):
    6894    "Returns a list of the CREATE TABLE SQL statements for the given app."
    69     from django.db import models
     95    from django.db import models, model_connection_name, _default
    7096    from django.conf import settings
    7197
    7298    if settings.DATABASE_ENGINE == 'dummy':
     
    81107    # generate invalid SQL (leaving models out of known_models is harmless, so
    82108    # we can be conservative).
    83109    app_models = models.get_models(app)
    84     final_output = []
    85110    known_models = set([model for model in installed_models(table_list()) if model not in app_models])
    86111    pending_references = {}
    87112
     113    connection_output = {}
     114   
    88115    for model in app_models:
     116        connection_name = model_connection_name(model)
     117        f_output = connection_output.setdefault(connection_name, [])
    89118        output, references = sql_model_create(model, style, known_models)
    90         final_output.extend(output)
     119        f_output.extend(output)
    91120        for refto, refs in references.items():
    92121            pending_references.setdefault(refto, []).extend(refs)
    93122            if refto in known_models:
    94                 final_output.extend(sql_for_pending_references(refto, style, pending_references))
    95         final_output.extend(sql_for_pending_references(model, style, pending_references))
     123                f_output.extend(sql_for_pending_references(refto, style, pending_references))
     124        f_output.extend(sql_for_pending_references(model, style, pending_references))
    96125        # Keep track of the fact that we've created the table for this model.
    97126        known_models.add(model)
    98127
    99128    # Create the many-to-many join tables.
    100129    for model in app_models:
    101         final_output.extend(many_to_many_sql_for_model(model, style))
     130        connection_name = model_connection_name(model)
     131        f_output = connection_output.setdefault(connection_name, [])
     132        f_output.extend(many_to_many_sql_for_model(model,style))
    102133
     134
    103135    # Handle references to tables that are from other apps
    104136    # but don't exist physically.
    105137    not_installed_models = set(pending_references.keys())
    106138    if not_installed_models:
     139        f_output = connection_output.setdefault(_default, [])
    107140        alter_sql = []
    108141        for model in not_installed_models:
    109142            alter_sql.extend(['-- ' + sql for sql in
    110143                sql_for_pending_references(model, style, pending_references)])
    111144        if alter_sql:
    112             final_output.append('-- The following references should be added but depend on non-existent tables:')
    113             final_output.extend(alter_sql)
     145            f_output.append('-- The following references should be added but depend on non-existent tables:')
     146            f_output.extend(alter_sql)
    114147
    115     return final_output
     148    return connection_output
    116149
    117150def sql_delete(app, style):
    118151    "Returns a list of the DROP TABLE SQL statements for the given app."
    119     from django.db import connection, models, get_introspection_module
     152    from django.db import models, model_connection_name
    120153    from django.db.backends.util import truncate_name
    121154    from django.contrib.contenttypes import generic
    122     introspection = get_introspection_module()
    123155
    124     # This should work even if a connection isn't available
    125     try:
    126         cursor = connection.cursor()
    127     except:
    128         cursor = None
     156    connection_output = {}
    129157
    130     # Figure out which tables already exist
    131     if cursor:
    132         table_names = introspection.get_table_list(cursor)
    133     else:
    134         table_names = []
    135     if connection.features.uses_case_insensitive_names:
    136         table_name_converter = lambda x: x.upper()
    137     else:
    138         table_name_converter = lambda x: x
    139 
    140     output = []
    141     qn = connection.ops.quote_name
    142 
    143158    # Output DROP TABLE statements for standard application tables.
    144159    to_delete = set()
    145160
    146161    references_to_delete = {}
    147162    app_models = models.get_models(app)
    148163    for model in app_models:
     164        connection = model._default_manager.db.connection
     165        introspection = model._default_manager.db.get_introspection_module()
     166        # This should work even if a connection isn't available
     167        try:
     168            cursor = connection.cursor()
     169        except:
     170            cursor = None
     171        # Figure out which tables already exist
     172        if cursor:
     173            table_names = introspection.get_table_list(cursor)
     174        else:
     175            table_names = []
     176        if connection.features.uses_case_insensitive_names:
     177            table_name_converter = lambda x: x.upper()
     178        else:
     179            table_name_converter = lambda x: x
     180
     181        qn = connection.ops.quote_name
     182
    149183        if cursor and table_name_converter(model._meta.db_table) in table_names:
    150184            # The table exists, so it needs to be dropped
    151185            opts = model._meta
     
    156190            to_delete.add(model)
    157191
    158192    for model in app_models:
     193        connection = model._default_manager.db.connection
     194        connection_name = model_connection_name(model)
     195        introspection = model._default_manager.db.get_introspection_module()
     196
     197        output = connection_output.setdefault(connection_name, [])
     198
     199        # This should work even if a connection isn't available
     200        try:
     201            cursor = connection.cursor()
     202        except:
     203            cursor = None
     204        # Figure out which tables already exist
     205        if cursor:
     206            table_names = introspection.get_table_list(cursor)
     207        else:
     208            table_names = []
     209        if connection.features.uses_case_insensitive_names:
     210            table_name_converter = str.upper
     211        else:
     212            table_name_converter = lambda x: x
     213
     214        qn = connection.ops.quote_name
     215
    159216        if cursor and table_name_converter(model._meta.db_table) in table_names:
    160217            # Drop the table now
    161218            output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
     
    180237
    181238    # Output DROP TABLE statements for many-to-many tables.
    182239    for model in app_models:
     240        connection = model._default_manager.db.connection
     241        connection_name = model_connection_name(model)
     242        introspection = model._default_manager.db.get_introspection_module()
     243
     244        output = connection_output.setdefault(connection_name, [])
     245
     246        # This should work even if a connection isn't available
     247        try:
     248            cursor = connection.cursor()
     249        except:
     250            cursor = None
     251        # Figure out which tables already exist
     252        if cursor:
     253            table_names = introspection.get_table_list(cursor)
     254        else:
     255            table_names = []
     256        if connection.features.uses_case_insensitive_names:
     257            table_name_converter = str.upper
     258        else:
     259            table_name_converter = lambda x: x
     260
     261        qn = connection.ops.quote_name
     262
    183263        opts = model._meta
    184264        for f in opts.local_many_to_many:
    185265            if isinstance(f.rel, generic.GenericRel):
     
    195275
    196276    # Close database connection explicitly, in case this output is being piped
    197277    # directly into a database client, to avoid locking issues.
    198     if cursor:
    199         cursor.close()
    200         connection.close()
     278    for model in app_models:
     279        connection = model._default_manager.db.connection
     280        try:
     281            cursor = connection.cursor()
     282        except:
     283            cursor = None
     284        if cursor:
     285            cursor.close()
     286            connection.close()
    201287
    202     return output[::-1] # Reverse it, to deal with table dependencies.
     288    return connection_output
    203289
    204290def sql_reset(app, style):
    205291    "Returns a list of the DROP TABLE SQL, then the CREATE TABLE SQL, for the given module."
    206     return sql_delete(app, style) + sql_all(app, style)
     292    connection_output = {}
     293    sql_dict = sql_delete(app, style)
     294    for connection_name, sql_list in sql_dict.items():
     295        output = connection_output.setdefault(connection_name, [])
     296        output.extend(sql_list)
     297    sql_dict = sql_all(app, style)
     298    for connection_name, sql_list in sql_dict.items():
     299        output = connection_output.setdefault(connection_name, [])
     300        output.extend(sql_list)
     301    return connection_output
    207302
    208 def sql_flush(style, only_django=False):
     303def sql_flush(connection, style, only_django=False):
    209304    """
    210305    Returns a list of the SQL statements used to flush the database.
    211306   
    212307    If only_django is True, then only table names that have associated Django
    213308    models and are in INSTALLED_APPS will be included.
    214309    """
    215     from django.db import connection
     310    from django.db import connections
    216311    if only_django:
    217         tables = django_table_list()
     312        tables = django_table_list_conn(connection)
    218313    else:
    219         tables = table_list()
    220     statements = connection.ops.sql_flush(style, tables, sequence_list())
    221     return statements
     314        tables = table_list_conn(connection)
     315    return [f for f in connections[connection].connection.ops.sql_flush(style, tables, sequence_list())]
    222316
    223317def sql_custom(app):
    224318    "Returns a list of the custom table modifying SQL statements for the given app."
    225319    from django.db.models import get_models
    226     output = []
     320    from django.db import model_connection_name
     321    connection_output = {}
    227322
    228323    app_models = get_models(app)
    229324    app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
    230325
    231326    for model in app_models:
    232         output.extend(custom_sql_for_model(model))
     327        connection_name = model_connection_name(model)
     328        output = connection_output.setdefault(connection_name, [])
     329        output.extend(map(str, custom_sql_for_model(model)))
     330    return connection_output
    233331
    234     return output
    235 
    236332def sql_indexes(app, style):
    237333    "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
    238     from django.db import models
    239     output = []
    240     for model in models.get_models(app):
    241         output.extend(sql_indexes_for_model(model, style))
    242     return output
     334    from django.db import model_connection_name
     335    from django.db.models import get_models
     336    connection_output = {}
     337    for model in get_models(app):
     338        opts = model._meta
     339        connection_name = model_connection_name(model)
     340        output = connection_output.setdefault(connection_name, [])
     341        output.extend(map(str, sql_indexes_for_model(model, style)))
     342    return connection_output
    243343
    244344def sql_all(app, style):
    245345    "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
    246     return sql_create(app, style) + sql_custom(app) + sql_indexes(app, style)
     346    connection_output = {}
     347    sql_dict = sql_create(app, style)
     348    for connection_name, sql_list in sql_dict.items():
     349        output = connection_output.setdefault(connection_name, [])
     350        output.extend(sql_list)
     351    sql_dict = sql_custom(app)
     352    for connection_name, sql_list in sql_dict.items():
     353        output = connection_output.setdefault(connection_name, [])
     354        output.extend(sql_list)
     355    sql_dict = sql_indexes(app, style)
     356    for connection_name, sql_list in sql_dict.items():
     357        output = connection_output.setdefault(connection_name, [])
     358        output.extend(sql_list)
     359    return connection_output
    247360
    248361def sql_model_create(model, style, known_models=set()):
    249362    """
    250363    Returns the SQL required to create a single model, as a tuple of:
    251364        (list_of_sql, pending_references_dict)
    252365    """
    253     from django.db import connection, models
     366    from django.db import models, model_connection_name, connections
    254367
    255368    opts = model._meta
    256369    final_output = []
    257370    table_output = []
    258371    pending_references = {}
     372    connection_name = model_connection_name(model)
     373    connection = connections[connection_name].connection
    259374    qn = connection.ops.quote_name
    260375    inline_references = connection.features.inline_fk_references
    261376    for f in opts.local_fields:
    262         col_type = f.db_type()
     377        col_type = f.db_type(connection_name)
    263378        tablespace = f.db_tablespace or opts.db_tablespace
    264379        if col_type is None:
    265380            # Skip ManyToManyFields, because they're not represented as
     
    291406        table_output.append(' '.join(field_output))
    292407    if opts.order_with_respect_to:
    293408        table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
    294             style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
     409            style.SQL_COLTYPE(models.IntegerField().db_type(connection_name)) + ' ' + \
    295410            style.SQL_KEYWORD('NULL'))
    296411    for field_constraints in opts.unique_together:
    297412        table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
     
    320435    """
    321436    Returns any ALTER TABLE statements to add constraints after the fact.
    322437    """
    323     from django.db import connection
     438    from django.db import connections, model_connection_name
    324439    from django.db.backends.util import truncate_name
    325440
     441    connection_name = model_connection_name(model)
     442    connection = connections[connection_name].connection
    326443    qn = connection.ops.quote_name
     444##    if hasattr(connection.ops, 'max_constraint_length'):
     445##        mnl = connection.ops.max_constraint_length
     446##    else:
     447##        mnl = connection.ops.max_name_length
    327448    final_output = []
    328449    if connection.features.supports_constraints:
    329450        opts = model._meta
     
    345466    return final_output
    346467
    347468def many_to_many_sql_for_model(model, style):
    348     from django.db import connection, models
     469    from django.db import models, connections, model_connection_name
    349470    from django.contrib.contenttypes import generic
    350471    from django.db.backends.util import truncate_name
    351472
    352473    opts = model._meta
    353474    final_output = []
     475    connection_name = model_connection_name(model)
     476    connection = connections[connection_name].connection
    354477    qn = connection.ops.quote_name
    355478    inline_references = connection.features.inline_fk_references
    356479    for f in opts.local_many_to_many:
     
    364487                style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
    365488            table_output.append('    %s %s %s%s,' %
    366489                (style.SQL_FIELD(qn('id')),
    367                 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
     490                style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type(connection_name)),
    368491                style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
    369492                tablespace_sql))
    370493            if inline_references:
    371494                deferred = []
    372495                table_output.append('    %s %s %s %s (%s)%s,' %
    373496                    (style.SQL_FIELD(qn(f.m2m_column_name())),
    374                     style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
     497                    style.SQL_COLTYPE(models.ForeignKey(model).db_type(connection_name)),
    375498                    style.SQL_KEYWORD('NOT NULL REFERENCES'),
    376499                    style.SQL_TABLE(qn(opts.db_table)),
    377500                    style.SQL_FIELD(qn(opts.pk.column)),
    378501                    connection.ops.deferrable_sql()))
    379502                table_output.append('    %s %s %s %s (%s)%s,' %
    380503                    (style.SQL_FIELD(qn(f.m2m_reverse_name())),
    381                     style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
     504                    style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type(connection_name)),
    382505                    style.SQL_KEYWORD('NOT NULL REFERENCES'),
    383506                    style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
    384507                    style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
     
    386509            else:
    387510                table_output.append('    %s %s %s,' %
    388511                    (style.SQL_FIELD(qn(f.m2m_column_name())),
    389                     style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
     512                    style.SQL_COLTYPE(models.ForeignKey(model).db_type(connection_name)),
    390513                    style.SQL_KEYWORD('NOT NULL')))
    391514                table_output.append('    %s %s %s,' %
    392515                    (style.SQL_FIELD(qn(f.m2m_reverse_name())),
    393                     style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
     516                    style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type(connection_name)),
    394517                    style.SQL_KEYWORD('NOT NULL')))
    395518                deferred = [
    396519                    (f.m2m_db_table(), f.m2m_column_name(), opts.db_table,
     
    456579
    457580def sql_indexes_for_model(model, style):
    458581    "Returns the CREATE INDEX SQL statements for a single model"
    459     from django.db import connection
    460582    output = []
    461583
     584    connection = model._default_manager.db.connection
    462585    qn = connection.ops.quote_name
    463586    for f in model._meta.local_fields:
    464587        if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
     
    489612        dispatcher.send(signal=models.signals.post_syncdb, sender=app,
    490613            app=app, created_models=created_models,
    491614            verbosity=verbosity, interactive=interactive)
     615
     616def sql_collate(connection_output, reverse=False):
     617    from django.db import _default
     618    final_output = []
     619    if len(connection_output.keys()) == 1:
     620        # all for the default connection
     621        for statements in connection_output.values():
     622            final_output.extend(statements)
     623            if reverse:
     624                final_output.reverse()
     625    else:
     626        for connection_name, statements in connection_output.items():
     627            if not statements:
     628                continue
     629            final_output.append(' -- The following statements are for connection: %s' % connection_name)
     630            if reverse:
     631                statements.reverse()
     632            final_output.extend(statements)
     633            final_output.append(' -- END statements for %s\n' %
     634                                connection_name)
     635    return '\n'.join(map(str, final_output))
  • django/core/management/validation.py

     
    1919    Returns number of errors.
    2020    """
    2121    from django.conf import settings
    22     from django.db import models, connection
     22    from django.db import connections, models, model_connection_name
    2323    from django.db.models.loading import get_app_errors
    2424    from django.db.models.fields.related import RelatedObject
    2525
     
    3030
    3131    for cls in models.get_models(app):
    3232        opts = cls._meta
     33        connection_name = model_connection_name(cls)
     34        connection = connections[connection_name].connection
    3335
    3436        # Do field-specific validation.
    3537        for f in opts.local_fields:
     
    7476            if f.rel:
    7577                if f.rel.to not in models.get_models():
    7678                    e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, f.rel.to))
     79
     80#MULTIDB TODO: Fix this to allow relations that span databases by splitting querys up
     81                rel_connection = model_connection_name(f.rel.to)
     82                if rel_connection != connection_name:
     83                    e.add(opts, "'%s' is configured to use connection '%s' but has relation with '%s', which is configured to use connection '%s'" % (cls.__name__, connection_name, f.rel.to.__name__, rel_connection))
     84
    7785                # it is a string and we could not find the model it refers to
    7886                # so skip the next section
    7987                if isinstance(f.rel.to, (str, unicode)):
  • django/contrib/contenttypes/generic.py

     
    44
    55from django import oldforms
    66from django.core.exceptions import ObjectDoesNotExist
    7 from django.db import connection
    87from django.db.models import signals
    98from django.db.models.fields.related import RelatedField, Field, ManyToManyRel
    109from django.db.models.loading import get_model
     
    154153    def get_internal_type(self):
    155154        return "ManyToManyField"
    156155
    157     def db_type(self):
     156    def db_type(self, connection):
    158157        # Since we're simulating a ManyToManyField, in effect, best return the
    159158        # same db_type as well.
    160159        return None
     
    184183        superclass = rel_model._default_manager.__class__
    185184        RelatedManager = create_generic_related_manager(superclass)
    186185
    187         qn = connection.ops.quote_name
     186        qn = rel_model._default_manager.db.connection.ops.quote_name
    188187
    189188        manager = RelatedManager(
    190189            model = rel_model,
  • django/contrib/auth/backends.py

     
    1 from django.db import connection
    21from django.contrib.auth.models import User
    32
    43try:
     
    2322    def get_group_permissions(self, user_obj):
    2423        "Returns a list of permission strings that this user has through his/her groups."
    2524        if not hasattr(user_obj, '_group_perm_cache'):
     25            connection = User._default_manager.db.connection
    2626            cursor = connection.cursor()
    2727            # The SQL below works out to the following, after DB quoting:
    2828            # cursor.execute("""
  • django/conf/global_settings.py

     
    122122DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
    123123DATABASE_OPTIONS = {}          # Set to empty dictionary for default.
    124124
     125# Optional named database connections in addition to the default.
     126OTHER_DATABASES = {}
     127
    125128# Host for sending e-mail.
    126129EMAIL_HOST = 'localhost'
    127130
     
    352355# If None, a name of 'test_' + DATABASE_NAME will be assumed
    353356TEST_DATABASE_NAME = None
    354357
     358# Tuple of other test databases to create. Names in this tuple
     359# are suffixes that will be appended to TEST_DATABASE_NAME
     360TEST_DATABASES = []
     361
     362# Models to assign to each test database. This must be a list of
     363# dicts, with each dict key being a name from TEST_DATABASES and value
     364# a list of models or app_labels that will use that database.
     365TEST_DATABASE_MODELS = []
     366
     367
    355368# Strings used to set the character set and collation order for the test
    356369# database. These values are passed literally to the server, so they are
    357370# backend-dependent. If None, no special settings are sent (system defaults are
  • tests/modeltests/multiple_databases/__init__.py

    Property changes on: tests\modeltests\multiple_databases
    ___________________________________________________________________
    Name: svn:ignore
       + *.pyc
    
    
     
     1pass
  • tests/modeltests/multiple_databases/models.py

     
     1"""
     2XXX. Using multiple database connections
     3
     4Django normally uses only a single database connection. However,
     5support is available for using any number of different, named
     6connections. Multiple database support is entirely optional and has
     7no impact on your application if you don't use it.
     8
     9Named connections are defined in your settings module. Create a
     10`OTHER_DATABASES` variable that is a dict, mapping connection names to their
     11particulars. The particulars are defined in a dict with the same keys
     12as the variable names as are used to define the default connection, with one
     13addition: MODELS.
     14
     15The MODELS item in an OTHER_DATABASES entry is a list of the apps and models
     16that will use that connection.
     17
     18Access to named connections is through `django.db.connections`, which
     19behaves like a dict: you access connections by name. Connections are
     20established lazily, when accessed.  `django.db.connections[database]`
     21holds a `ConnectionInfo` instance, with the attributes:
     22`DatabaseError`, `backend`, `get_introspection_module`,
     23`get_creation_module`, and `runshell`.
     24
     25To access a model's connection, use its manager. The connection is available
     26at `model._default_manager.db.connection`. To find the backend or other
     27connection metadata, use `model._meta.db` to access the full ConnectionInfo
     28with connection metadata.
     29"""
     30
     31from django.db import models
     32
     33class Artist(models.Model):
     34    name = models.CharField(max_length=100)
     35    alive = models.BooleanField(default=True)
     36   
     37    def __str__(self):
     38        return self.name
     39
     40   
     41class Opus(models.Model):
     42    artist = models.ForeignKey(Artist)
     43    name = models.CharField(max_length=100)
     44    year = models.IntegerField()
     45   
     46    def __str__(self):
     47        return "%s (%s)" % (self.name, self.year)
     48
     49
     50class Widget(models.Model):
     51    code = models.CharField(max_length=10, unique=True)
     52    weight = models.IntegerField()
     53
     54    def __str__(self):
     55        return self.code
     56
     57
     58class DooHickey(models.Model):
     59    name = models.CharField(max_length=50)
     60    widgets = models.ManyToManyField(Widget, related_name='doohickeys')
     61   
     62    def __str__(self):
     63        return self.name
     64
     65
     66class Vehicle(models.Model):
     67    make = models.CharField(max_length=20)
     68    model = models.CharField(max_length=20)
     69    year = models.IntegerField()
     70
     71    def __str__(self):
     72        return "%d %s %s" % (self.year, self.make, self.model)
     73
     74
     75__test__ = {'API_TESTS': """
     76
     77# See what connections are defined. django.db.connections acts like a dict.
     78>>> from django.db import connection, connections, _default, model_connection_name
     79>>> from django.conf import settings
     80
     81# Connections are referenced by name
     82>>> connections['_a']
     83Connection: ...
     84>>> connections['_b']
     85Connection: ...
     86
     87# Let's see what connections are available. The default connection is always
     88# included in connections as well, and may be accessed as connections[_default].
     89
     90>>> connection_names = connections.keys()
     91>>> connection_names.sort()
     92>>> connection_names
     93[<default>, '_a', '_b']
     94   
     95# Invalid connection names raise ImproperlyConfigured
     96
     97>>> connections['bad']
     98Traceback (most recent call last):
     99 ...
     100ImproperlyConfigured: No database connection 'bad' has been configured
     101
     102# The model_connection_name() function will tell you the name of the
     103# connection that a model is configured to use.
     104
     105>>> model_connection_name(Artist)
     106'_a'
     107>>> model_connection_name(Widget)
     108'_b'
     109>>> model_connection_name(Vehicle) is _default
     110True
     111>>> a = Artist(name="Paul Klee", alive=False)
     112>>> a.save()
     113>>> w = Widget(code='100x2r', weight=1000)
     114>>> w.save()
     115>>> v = Vehicle(make='Chevy', model='Camaro', year='1966')
     116>>> v.save()
     117>>> artists = Artist.objects.all()
     118>>> list(artists)
     119[<Artist: Paul Klee>]
     120
     121# Models can access their connections through the db property of their
     122# default manager.
     123
     124>>> paul = _[0]
     125>>> Artist.objects.db
     126Connection: ... (ENGINE=... NAME=...)
     127>>> paul._default_manager.db
     128Connection: ... (ENGINE=... NAME=...)
     129
     130# When transactions are not managed, model save will commit only
     131# for the model's connection.
     132
     133>>> from django.db import transaction
     134>>> transaction.enter_transaction_management()
     135>>> transaction.managed(False)
     136>>> a = Artist(name="Joan Miro", alive=False)
     137>>> w = Widget(code="99rbln", weight=1)
     138>>> a.save()
     139
     140# Only connection '_a' is committed, so if we rollback
     141# all connections we'll forget the new Widget.
     142
     143>>> transaction.rollback()
     144>>> list(Artist.objects.all())
     145[<Artist: Paul Klee>, <Artist: Joan Miro>]
     146>>> list(Widget.objects.all())
     147[<Widget: 100x2r>]
     148
     149# Managed transaction state applies across all connections.
     150
     151>>> transaction.managed(True)
     152
     153# When managed, just as when using a single connection, updates are
     154# not committed until a commit is issued.
     155
     156>>> a = Artist(name="Pablo Picasso", alive=False)
     157>>> a.save()
     158>>> w = Widget(code="99rbln", weight=1)
     159>>> w.save()
     160>>> v = Vehicle(make='Pontiac', model='Fiero', year='1987')
     161>>> v.save()
     162
     163# The connections argument may be passed to commit, rollback, and the
     164# commit_on_success decorator as a keyword argument, as the first (for
     165# commit and rollback) or second (for the decorator) positional
     166# argument. It may be passed as a ConnectionInfo object, a connection
     167# (DatabaseWrapper) object, a connection name, or a list or dict of
     168# ConnectionInfo objects, connection objects, or connection names. If a
     169# dict is passed, the keys are ignored and the values used as the list
     170# of connections to commit, rollback, etc.
     171
     172>>> transaction.commit(connections['_b'])
     173>>> transaction.commit('_b')
     174>>> transaction.commit(connections='_b')
     175>>> transaction.commit(connections=['_b'])
     176>>> transaction.commit(['_a', '_b'])
     177>>> transaction.commit(connections)
     178
     179# When the connections argument is omitted entirely, the transaction
     180# command applies to all connections. Here we have committed
     181# connections 'django_test_db_a' and 'django_test_db_b', but not the
     182# default connection, so the new vehicle is lost on rollback.
     183
     184>>> transaction.rollback()
     185>>> list(Artist.objects.all())
     186[<Artist: Paul Klee>, <Artist: Joan Miro>, <Artist: Pablo Picasso>]
     187>>> list(Widget.objects.all())
     188[<Widget: 100x2r>, <Widget: 99rbln>]
     189>>> list(Vehicle.objects.all())
     190[<Vehicle: 1966 Chevy Camaro>]
     191>>> transaction.rollback()
     192>>> transaction.managed(False)
     193>>> transaction.leave_transaction_management()
     194
     195# Of course, relations and all other normal database operations work
     196# with models that use named connections just the same as with models
     197# that use the default connection. The only caveat is that you can't
     198# use a relation between two models that are stored in different
     199# databases. Note that that doesn't mean that two models using
     200# different connection *names* can't be related; only that in the the
     201# context in which they are used, if you use the relation, the
     202# connections named by the two models must resolve to the same
     203# database.
     204
     205>>> a = Artist.objects.get(name="Paul Klee")
     206>>> list(a.opus_set.all())
     207[]
     208>>> a.opus_set.create(name="Magic Garden", year="1926")
     209<Opus: Magic Garden (1926)>
     210>>> list(a.opus_set.all())
     211[<Opus: Magic Garden (1926)>]
     212>>> d = DooHickey(name='Thing')
     213>>> d.save()
     214>>> d.widgets.create(code='d101', weight=92)
     215<Widget: d101>
     216>>> list(d.widgets.all())
     217[<Widget: d101>]
     218>>> w = Widget.objects.get(code='d101')
     219>>> list(w.doohickeys.all())
     220[<DooHickey: Thing>]
     221"""}
  • tests/regressiontests/manager_db/tests.py

    Property changes on: tests\regressiontests\manager_db
    ___________________________________________________________________
    Name: svn:ignore
       + *.pyc
    
    
     
     1import unittest
     2from regressiontests.manager_db.models import Insect
     3
     4class TestManagerDBAccess(unittest.TestCase):
     5
     6    def test_db_property(self):
     7        m = Insect.objects
     8        db = Insect.objects.db
     9        assert db
     10        assert db.connection
     11        assert db.connection.cursor
     12        assert db.backend
     13        assert db.connection.ops.quote_name
     14        assert db.get_creation_module
     15
     16if __name__ == '__main__':
     17    unittest.main()
  • tests/regressiontests/manager_db/models.py

     
     1from django.db import models
     2
     3class Insect(models.Model):
     4    common_name = models.CharField(max_length=64)
     5    latin_name = models.CharField(max_length=128)
  • tests/regressiontests/thread_isolation/tests.py

    Property changes on: tests\regressiontests\thread_isolation
    ___________________________________________________________________
    Name: svn:ignore
       + *.pyc
    
    
     
     1# tests that db settings can be different in different threads
     2#
     3#
     4#    What's going on here:
     5#
     6#    Simulating multiple web requests in a threaded environment, one in
     7#    which settings are different for each request. So we replace
     8#    django.conf.settings with a thread local, with different
     9#    configurations in each thread, and then fire off three
     10#    simultaneous requests (using a condition to sync them up), and
     11#    test that each thread sees its own settings and the models in each
     12#    thread attempt to connect to the correct database as per their
     13#    settings.
     14#
     15
     16
     17import copy
     18import os
     19import sys
     20import threading
     21import unittest
     22from thread import get_ident
     23
     24from django.conf import settings, UserSettingsHolder
     25from django.core.handlers.wsgi import WSGIHandler
     26from django.db import model_connection_name, _default, connection, connections
     27from regressiontests.request_isolation.tests import MockHandler
     28from regressiontests.thread_isolation.models import *
     29
     30try:
     31    # Only exists in Python 2.4+
     32    from threading import local
     33except ImportError:
     34    # Import copy of _thread_local.py from Python 2.4
     35    from django.utils._threading_local import local
     36
     37# helpers
     38EV = threading.Event()
     39
     40class LocalSettings:
     41    """Settings holder that allows thread-local overrides of defaults.
     42    """
     43    def __init__(self, defaults):
     44        self._defaults = defaults
     45        self._local = local()
     46
     47    def __getattr__(self, attr):
     48        if attr in ('_defaults', '_local'):
     49            return self.__dict__[attr]
     50        _local = self.__dict__['_local']
     51        _defaults = self.__dict__['_defaults']
     52        debug("LS get %s (%s)", attr, hasattr(_local, attr))
     53        if not hasattr(_local, attr):
     54            # Make sure everything we return is the local version; this
     55            # avoids sets to deep datastructures overwriting the defaults
     56            setattr(_local, attr, copy.deepcopy(getattr(_defaults, attr)))
     57        return getattr(_local, attr)
     58
     59    def __setattr__(self, attr, val):
     60        if attr in ('_defaults', '_local'):
     61            self.__dict__[attr] = val
     62        else:
     63            debug("LS set local %s = %s", attr, val)
     64            setattr(self.__dict__['_local'], attr, val)
     65
     66def thread_two(func, *arg):
     67    def start():
     68        # from django.conf import settings
     69        settings.OTHER_DATABASES['_b']['MODELS'] = []
     70
     71        debug("t2 ODB: %s", settings.OTHER_DATABASES)
     72        debug("t2 waiting")
     73        EV.wait(2.0)
     74        func(*arg)
     75        debug("t2 complete")
     76    t2 = threading.Thread(target=start)
     77    t2.start()
     78    return t2
     79
     80def thread_three(func, *arg):
     81    def start():
     82        # from django.conf import settings           
     83        settings.OTHER_DATABASES['_b']['MODELS'] = ['ti.MY']
     84        settings.OTHER_DATABASES['_b'], \
     85            settings.OTHER_DATABASES['_a'] = \
     86            settings.OTHER_DATABASES['_a'], \
     87            settings.OTHER_DATABASES['_b']
     88
     89        settings.DATABASE_NAME = \
     90            settings.OTHER_DATABASES['_a']['DATABASE_NAME']
     91
     92        debug("t3 ODB: %s", settings.OTHER_DATABASES)
     93        debug("3 %s: start: default: %s", get_ident(), settings.DATABASE_NAME)
     94        debug("3 %s: start: conn: %s", get_ident(),
     95              connection.settings.DATABASE_NAME)
     96       
     97        debug("t3 waiting")
     98        EV.wait(2.0)
     99        func(*arg)
     100        debug("t3 complete")
     101    t3 = threading.Thread(target=start)
     102    t3.start()
     103    return t3
     104
     105def debug(*arg):
     106    pass
     107##    msg, arg = arg[0], arg[1:]
     108##    print msg % arg
     109
     110def start_response(code, headers):
     111    debug("start response: %s %s", code, headers)
     112    pass
     113   
     114class TestThreadIsolation(unittest.TestCase):
     115    # event used to synchronize threads so we can be sure they are running
     116    # together
     117    lock = threading.RLock()
     118    errors = []
     119   
     120    def setUp(self):
     121        debug("setup")
     122        self.settings = settings._target
     123        settings._target = UserSettingsHolder(copy.deepcopy(settings._target))
     124        settings.OTHER_DATABASES['_a']['MODELS'] =  ['ti.MX']
     125        settings.OTHER_DATABASES['_b']['MODELS'] = ['ti.MY']
     126
     127        # normal settings holders aren't thread-safe, so we need to substitute
     128        # one that is (and so allows per-thread settings)
     129        holder = settings._target
     130        settings._target = LocalSettings(holder)
     131
     132    def teardown(self):
     133        debug("teardown")
     134        settings._target = self.settings
     135
     136    def add_thread_error(self, err):
     137        self.lock.acquire()
     138        try:
     139            self.errors.append(err)
     140        finally:
     141            self.lock.release()
     142
     143    def thread_errors(self):
     144        self.lock.acquire()
     145        try:
     146            return self.errors[:]
     147        finally:
     148            self.lock.release()
     149           
     150    def request_one(self, request):
     151        """Start out with settings as originally configured"""
     152        from django.conf import settings
     153        debug("request_one: %s", settings.OTHER_DATABASES)
     154
     155        self.assertEqual(model_connection_name(MQ), _default)
     156        self.assertEqual(model_connection_name(MX), '_a')
     157        self.assertEqual(
     158            MX._default_manager.db.connection.settings.DATABASE_NAME,
     159            settings.OTHER_DATABASES['_a']['DATABASE_NAME'])
     160        self.assertEqual(model_connection_name(MY), '_b')
     161        self.assertEqual(
     162            MY._default_manager.db.connection.settings.DATABASE_NAME,
     163            settings.OTHER_DATABASES['_b']['DATABASE_NAME'])
     164        self.assert_(MQ._default_manager.db.connection is
     165                     connections[_default].connection)
     166        self.assertEqual(
     167            MQ._default_manager.db.connection.settings.DATABASE_NAME,
     168            settings.DATABASE_NAME)
     169        self.assertEqual(connection.settings.DATABASE_NAME,
     170                         settings.DATABASE_NAME)
     171
     172    def request_two(self, request):
     173        """Between the first and second requests, settings change to assign
     174        model MY to a different connection
     175        """
     176        # from django.conf import settings
     177        debug("request_two: %s", settings.OTHER_DATABASES)
     178
     179        try:
     180            self.assertEqual(model_connection_name(MQ), _default)
     181            self.assertEqual(model_connection_name(MX), '_a')
     182            self.assertEqual(
     183                MX._default_manager.db.connection.settings.DATABASE_NAME,
     184                settings.OTHER_DATABASES['_a']['DATABASE_NAME'])
     185            self.assertEqual(model_connection_name(MY), _default)
     186            self.assertEqual(
     187                MY._default_manager.db.connection.settings.DATABASE_NAME,
     188                settings.DATABASE_NAME)
     189            self.assert_(MQ._default_manager.db.connection is
     190                         connections[_default].connection)
     191            self.assertEqual(
     192                MQ._default_manager.db.connection.settings.DATABASE_NAME,
     193                settings.DATABASE_NAME)
     194            self.assertEqual(connection.settings.DATABASE_NAME,
     195                             settings.DATABASE_NAME)
     196        except:
     197            self.add_thread_error(sys.exc_info())
     198
     199    def request_three(self, request):
     200        """Between the 2nd and 3rd requests, the settings at the names in
     201        OTHER_DATABASES have changed.
     202        """
     203        # from django.conf import settings
     204        debug("3 %s: %s", get_ident(), settings.OTHER_DATABASES)
     205        debug("3 %s: default: %s", get_ident(), settings.DATABASE_NAME)
     206        debug("3 %s: conn: %s", get_ident(),
     207              connection.settings.DATABASE_NAME)
     208        try:
     209            self.assertEqual(model_connection_name(MQ), _default)
     210            self.assertEqual(model_connection_name(MX), '_b')
     211            self.assertEqual(
     212                MX._default_manager.db.connection.settings.DATABASE_NAME,
     213                settings.OTHER_DATABASES['_b']['DATABASE_NAME'])
     214            self.assertEqual(model_connection_name(MY), '_a')
     215            self.assertEqual(
     216                MY._default_manager.db.connection.settings.DATABASE_NAME,
     217                settings.OTHER_DATABASES['_a']['DATABASE_NAME'])
     218            self.assert_(MQ._default_manager.db.connection is
     219                         connections[_default].connection)
     220            self.assertEqual(
     221                connection.settings.DATABASE_NAME,
     222                settings.OTHER_DATABASES['_a']['DATABASE_NAME'])
     223        except:
     224            self.add_thread_error(sys.exc_info())
     225       
     226    def test_thread_isolation(self):
     227       
     228        debug("running tests")
     229
     230        env = os.environ.copy()
     231        env['PATH_INFO'] = '/'
     232        env['REQUEST_METHOD'] = 'GET'
     233
     234        t2 = thread_two(MockHandler(self.request_two), env, start_response)
     235        t3 = thread_three(MockHandler(self.request_three), env, start_response)
     236
     237        try:
     238            EV.set()
     239            MockHandler(self.request_one)(env, start_response)
     240        finally:
     241            t2.join()
     242            t3.join()
     243            err = self.thread_errors()
     244            if err:
     245                import traceback
     246                for e in err:
     247                    traceback.print_exception(*e)
     248                    raise AssertionError("%s thread%s failed" %
     249                                         (len(err), len(err) > 1 and 's' or
     250                                          ''))
     251               
  • tests/regressiontests/thread_isolation/models.py

     
     1from django.db import models
     2
     3# models
     4class MQ(models.Model):
     5    val = models.CharField(max_length=10)
     6    class Meta:
     7        app_label = 'ti'
     8
     9
     10class MX(models.Model):
     11    val = models.CharField(max_length=10)
     12    class Meta:
     13        app_label = 'ti'
     14
     15       
     16class MY(models.Model):
     17    val = models.CharField(max_length=10)
     18    class Meta:
     19        app_label = 'ti'
  • tests/regressiontests/request_isolation/tests.py

    Property changes on: tests\regressiontests\request_isolation
    ___________________________________________________________________
    Name: svn:ignore
       + *.pyc
    
    
     
     1# tests that db settings can change between requests
     2import copy
     3import os
     4import unittest
     5from django.conf import settings, UserSettingsHolder
     6from django.core.handlers.wsgi import WSGIHandler
     7from django.db import models, model_connection_name, _default, connection
     8from django.http import HttpResponse
     9from regressiontests.request_isolation.models import *
     10
     11
     12# helpers
     13class MockHandler(WSGIHandler):
     14
     15    def __init__(self, test):
     16        self.test = test
     17        super(MockHandler, self).__init__()
     18       
     19    def get_response(self, request):
     20        # debug("mock handler answering %s, %s", path, request)
     21        return HttpResponse(self.test(request))
     22
     23
     24def debug(*arg):
     25    pass
     26    # msg, arg = arg[0], arg[1:]
     27    # print msg % arg
     28
     29
     30def start_response(code, headers):
     31    debug("start response: %s %s", code, headers)
     32    pass
     33
     34# tests
     35class TestRequestIsolation(unittest.TestCase):
     36
     37    def setUp(self):
     38        debug("setup")
     39        self.settings = settings._target
     40        settings._target = UserSettingsHolder(copy.deepcopy(settings._target))
     41        settings.OTHER_DATABASES['_a']['MODELS'] = ['ri.MX']
     42        settings.OTHER_DATABASES['_b']['MODELS'] = ['ri.MY']
     43
     44    def tearDown(self):
     45        debug("teardown")
     46        settings._target = self.settings
     47
     48    def testRequestIsolation(self):
     49        env = os.environ.copy()
     50        env['PATH_INFO'] = '/'
     51        env['REQUEST_METHOD'] = 'GET'
     52
     53        def request_one(request):
     54            """Start out with settings as originally configured"""
     55            self.assertEqual(model_connection_name(MX), '_a')
     56            self.assertEqual(
     57                MX._default_manager.db.connection.settings.DATABASE_NAME,
     58                settings.OTHER_DATABASES['_a']['DATABASE_NAME'])
     59            self.assertEqual(model_connection_name(MY), '_b')
     60            self.assertEqual(
     61                MY._default_manager.db.connection.settings.DATABASE_NAME,
     62                settings.OTHER_DATABASES['_b']['DATABASE_NAME'])
     63
     64        def request_two(request):
     65            """Between the first and second requests, settings change to assign
     66            model MY to a different connection
     67            """
     68            self.assertEqual(model_connection_name(MX), '_a')
     69            self.assertEqual(
     70                MX._default_manager.db.connection.settings.DATABASE_NAME,
     71                settings.OTHER_DATABASES['_a']['DATABASE_NAME'])
     72            self.assertEqual(model_connection_name(MY), _default)
     73            self.assertEqual(
     74                MY._default_manager.db.connection.settings.DATABASE_NAME,
     75                settings.DATABASE_NAME)
     76
     77        def request_three(request):
     78            """Between the 2nd and 3rd requests, the settings at the names in
     79            OTHER_DATABASES have changed.
     80            """
     81            self.assertEqual(model_connection_name(MX), '_b')
     82            self.assertEqual(
     83                MX._default_manager.db.connection.settings.DATABASE_NAME,
     84                settings.OTHER_DATABASES['_b']['DATABASE_NAME'])
     85            self.assertEqual(model_connection_name(MY), '_a')
     86            self.assertEqual(
     87                MY._default_manager.db.connection.settings.DATABASE_NAME,
     88                settings.OTHER_DATABASES['_a']['DATABASE_NAME'])
     89   
     90        MockHandler(request_one)(env, start_response)
     91
     92        settings.OTHER_DATABASES['_b']['MODELS'] = []
     93        MockHandler(request_two)(env, start_response)
     94
     95        settings.OTHER_DATABASES['_b']['MODELS'] = ['ri.MY']
     96        settings.OTHER_DATABASES['_b'], \
     97            settings.OTHER_DATABASES['_a'] = \
     98            settings.OTHER_DATABASES['_a'], \
     99            settings.OTHER_DATABASES['_b']
     100        MockHandler(request_three)(env, start_response)
  • tests/regressiontests/request_isolation/models.py

     
     1from django.db import models
     2
     3# models
     4class MX(models.Model):
     5    val = models.CharField(max_length=10)
     6    class Meta:
     7        app_label = 'ri'
     8
     9       
     10class MY(models.Model):
     11    val = models.CharField(max_length=10)
     12    class Meta:
     13        app_label = 'ri'
  • tests/runtests.py

     
    1212
    1313
    1414CONTRIB_DIR_NAME = 'django.contrib'
     15TEST_OTHER_DATABASES = {
     16    '_a': { 'DATABASE_NAME': 'django_test_a.db',
     17            'MODELS': [ 'multiple_databases.Artist',
     18            'multiple_databases.Opus' ]},
     19    '_b': { 'DATABASE_NAME': 'django_test_b.db',
     20            'MODELS': [ 'multiple_databases.Widget',
     21            'multiple_databases.DooHickey' ]}
     22}
    1523MODEL_TESTS_DIR_NAME = 'modeltests'
    1624REGRESSION_TESTS_DIR_NAME = 'regressiontests'
    1725
     
    99107
    100108    # Redirect some settings for the duration of these tests.
    101109    settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS
     110    settings.TEST_OTHER_DATABASES = TEST_OTHER_DATABASES
    102111    settings.ROOT_URLCONF = 'urls'
    103112    settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), TEST_TEMPLATE_DIR),)
    104113    settings.USE_I18N = True
  • docs/multiple_database_support.txt

     
     1========================
     2Using Multiple Databases
     3========================
     4
     5Standard Django practice is to use a single database connection for
     6all models in all applications. However, Django supports configuring
     7and using multiple database connections on a per-application, per-model
     8or an ad-hoc basis. Using multiple database connections is optional.
     9
     10Configuring other database connections
     11======================================
     12
     13Django's default database connection is configured via the settings
     14DATABASE_ENGINE, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD,
     15DATABASE_HOST, and DATABASE_PORT. Other connections are configured via
     16the OTHER_DATABASES setting. Define OTHER_DATABASES as a dict, with a
     17name for each connection as the key and a dict of settings as the
     18value. In each OTHER_DATABASES entry (called a "named connection"),
     19the keys are the same as the DATABASE_ENGINE, etc, settings used to
     20configure the default connection. All keys are optional; any that are
     21missing in a named connection's settings will inherit their values
     22from the default connection.
     23
     24Here's an example::
     25
     26    DATABASE_ENGINE = 'postgresql'
     27    DATABASE_NAME = 'django_apps'
     28    DATABASE_USER = 'default_user'
     29    DATABASE_PASSWORD = 'xxx'
     30       
     31    OTHER_DATABASES = {
     32        'local': { 'DATABASE_ENGINE': 'sqlite3',
     33                   'DATABASE_NAME': '/tmp/cache.db' },
     34        'public': { 'DATABASE_HOST': 'public',
     35                    'DATABASE_USER': 'public_user',
     36                    'DATABASE_PASSWORD': 'xxx' }
     37        'private': { 'DATABASE_HOST': 'private',
     38                     'DATABASE_USER': 'private_user',
     39                     'DATABASE_PASSWORD': 'xxx' }
     40    }
     41
     42In addition to the DATABASE_* settings, each named connection in
     43OTHER_DATABASES may optionally include a MODELS setting. This should
     44be a list of app or app.model names, and is used to configure which
     45models should use this connection instead of the default connection.
     46
     47Here's the example above, with ``MODELS``::
     48
     49    OTHER_DATABASES = {
     50        'local': { 'DATABASE_ENGINE': 'sqlite3',
     51                   'DATABASE_NAME': '/tmp/cache.db',
     52                   # A model name: only the model ContentItem
     53                   # with the app_label myapp will use this connection
     54                   'MODELS': ['myapp.ContentItem'] },
     55        'public': { 'DATABASE_HOST': 'public',
     56                    'DATABASE_USER': 'public_user',
     57                    'DATABASE_PASSWORD': 'xxx',
     58                    # Two models in myapp will use the connection
     59                    # named 'public', as will ALL models in
     60                    # django.contribe.comments
     61                    'MODELS': ['myapp.Blog','myapp.Article',
     62                               'django.contrib.comments' ] }
     63        # No models or apps are configured to use the private db
     64        'private': { 'DATABASE_HOST': 'private',
     65                     'DATABASE_USER': 'private_user',
     66                     'DATABASE_PASSWORD': 'xxx' }
     67    }
     68
     69Accessing a model's connection
     70==============================
     71
     72Each manager has a ``db`` attribute that can be used to access the model's
     73connection. Access the ``db`` attribute of a model's manager to obtain the
     74model's currently configured connection.
     75
     76Example::
     77
     78    from django.db import models
     79
     80    class Blog(models.Model)
     81        name = models.CharField(maxlength=50)
     82
     83    class Article(models.Model)
     84        blog = models.ForeignKey(Blog)
     85        title = models.CharField(maxlength=100)
     86        slug = models.SlugField()
     87        summary = models.CharField(maxlength=500)
     88        body = models.TextField()
     89
     90    class ContentItem(models.Model)
     91        slug = models.SlugField()
     92        mimetype = models.CharField(maxlength=50)
     93        file = models.FileField()
     94       
     95    # Get a ConnectionInfo instance that describes the connection
     96    article_db = Article.objects.db
     97   
     98    # Get a connection and a cursor
     99    connection = article_db.connection
     100    cursor = connection.cursor()
     101
     102    # Get the ``quote_name`` function from the backend
     103    qn = article_db.backend.quote_name
     104
     105Ordinarily you won't have to access a model's connection directly;
     106just use the model and manager normally and they will use the
     107connection configured for the model.
     108
     109ConnectionInfo objects
     110======================
     111
     112FIXME Describe the ConnectionInfo object and each of its attributes.
     113
     114
     115Accessing connections by name
     116=============================
     117
     118Access named connections directly through
     119``django.db.connections``. Each entry in ``django.db.connections`` is
     120a ``ConnectionInfo`` instance bound to the settings configured in the
     121OTHER_DATABASES entry under the same key.
     122
     123Example::
     124
     125    from django.db import connections
     126
     127    private_db = connections['private']
     128    cursor = private_db.connection.cursor()
     129
     130
     131Using transactions with other database connections
     132==================================================
     133
     134Transaction managed state applies across all connections
     135commit/rollback apply to all connections by default
     136but you can specify individual connections or lists or dicts of connections
     137
     138
     139Changing model connections on the fly
     140=====================================
     141
     142Here's an example of primitive mirroring::
     143 
     144    # Read all articles from the private db
     145    # Note that we pull the articles into a list; this is necessary
     146    # because query sets are lazy. If we were to change the model's
     147    # connection without copying the articles into a local list, we'd
     148    # wind up reading from public instead of private.
     149
     150    Article.objects.db = connections['private']
     151    all_articles = list(Article.objects.all())
     152   
     153    # Save each article in the public db
     154    Article.objects.db = connections['public']
     155    for article in all_articles:
     156        article.save()
     157
     158Thread and request isolation
     159============================
     160
     161connections close after each request
     162connection settings are thread-local
     163
  • docs/settings.txt

     
    733733See `allowed date format strings`_. See also ``DATE_FORMAT``,
    734734``DATETIME_FORMAT``, ``TIME_FORMAT`` and ``YEAR_MONTH_FORMAT``.
    735735
     736OTHER_DATABASES
     737---------------
     738
     739Default: ``{}``
     740
     741Other database connections to use in addition to the default connection. See the `multiple database support docs`_.
     742
    736743PREPEND_WWW
    737744-----------
    738745
Back to Top