Ticket #4747: mdb.patch

File mdb.patch, 203.1 KB (added by ben <ben.fordnz@…>, 17 years ago)

Full Patch -r4189:5589

  • django/test/utils.py

    === django/test/utils.py
    ==================================================================
     
    11import sys, time
    22from django.conf import settings
    3 from django.db import connection, backend, get_creation_module
     3from django.db import connection, transaction, backend, \
     4                connection_info, connections, get_creation_module
    45from django.core import management, mail
    56from django.core import management, mail
    67from django.dispatch import dispatcher
     
    1213TEST_DATABASE_PREFIX = 'test_'
    1314
    1415def instrumented_test_render(self, context):
    15     """An instrumented Template render method, providing a signal
    16     that can be intercepted by the test system Client
    17    
    1816    """
     17    An instrumented Template render method, providing a signal that can be
     18    intercepted by the test system Client.
     19    """
    1920    dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context)
    2021    return self.nodelist.render(context)
     22
     23def instrumented_test_iter_render(self, context):
     24    """
     25    An instrumented Template iter_render method, providing a signal that can be
     26    intercepted by the test system Client.
     27    """
     28    for chunk in self.nodelist.iter_render(context):
     29        yield chunk
     30    dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context)
    2131   
    2232class TestSMTPConnection(object):
    2333    """A substitute SMTP connection for use during test sessions.
     
    4555       
    4656    """
    4757    Template.original_render = Template.render
     58    Template.original_iter_render = Template.iter_render
    4859    Template.render = instrumented_test_render
     60    Template.iter_render = instrumented_test_render
    4961   
    5062    mail.original_SMTPConnection = mail.SMTPConnection
    5163    mail.SMTPConnection = TestSMTPConnection
     
    6072       
    6173    """
    6274    Template.render = Template.original_render
    63     del Template.original_render
     75    Template.iter_render = Template.original_iter_render
     76    del Template.original_render, Template.original_iter_render
    6477   
    6578    mail.SMTPConnection = mail.original_SMTPConnection
    6679    del mail.original_SMTPConnection
     
    7386        connection.connection.autocommit(True)
    7487    elif hasattr(connection.connection, "set_isolation_level"):
    7588        connection.connection.set_isolation_level(0)
    76 
     89       
    7790def get_mysql_create_suffix():
    7891    suffix = []
    7992    if settings.TEST_DATABASE_CHARSET:
     
    97110   
    98111    if verbosity >= 1:
    99112        print "Creating test database..."
     113       
    100114    # If we're using SQLite, it's more convenient to test against an
    101115    # in-memory database.
    102116    if settings.DATABASE_ENGINE == "sqlite3":
    103         TEST_DATABASE_NAME = ":memory:"
     117        TEST_DATABASE_NAME = "/home/ben/test.db" #":memory:"
     118        if verbosity >= 2:
     119            print "Using in-memory sqlite database for testing"
    104120    else:
    105121        suffix = {
    106122            'postgresql': get_postgresql_create_suffix,
     
    112128            TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
    113129        else:
    114130            TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
    115        
     131
     132        qn = backend.quote_name
    116133        # Create the test database and connect to it. We need to autocommit
    117134        # if the database supports it because PostgreSQL doesn't allow
    118135        # CREATE/DROP DATABASE statements within transactions.
    119136        cursor = connection.cursor()
    120137        _set_autocommit(connection)
    121138        try:
    122             cursor.execute("CREATE DATABASE %s %s" % (backend.quote_name(TEST_DATABASE_NAME), suffix))
     139            cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))
    123140        except Exception, e:           
    124141            sys.stderr.write("Got an error creating the test database: %s\n" % e)
    125142            if not autoclobber:
     
    128145                try:
    129146                    if verbosity >= 1:
    130147                        print "Destroying old test database..."               
    131                     cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME))
     148                    cursor.execute("DROP DATABASE %s" % qn(TEST_DATABASE_NAME))
    132149                    if verbosity >= 1:
    133150                        print "Creating test database..."
    134                     cursor.execute("CREATE DATABASE %s %s" % (backend.quote_name(TEST_DATABASE_NAME), suffix))
     151                    cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))
    135152                except Exception, e:
    136153                    sys.stderr.write("Got an error recreating the test database: %s\n" % e)
    137154                    sys.exit(2)
     
    148165    # the side effect of initializing the test database.
    149166    cursor = connection.cursor()
    150167
    151 def destroy_test_db(old_database_name, verbosity=1):
     168    # Fill OTHER_DATABASES with the TEST_DATABASES settings,
     169    # and connect each named connection to the test database.
     170    test_databases = {}
     171    for db_name in settings.TEST_DATABASES:
     172        db_st = {'DATABASE_NAME': TEST_DATABASE_NAME}
     173        if db_name in settings.TEST_DATABASE_MODELS:
     174            db_st['MODELS'] = settings.TEST_DATABASE_MODELS.get(db_name, [])
     175        test_databases[db_name] = db_st
     176    settings.OTHER_DATABASES = test_databases
     177   
     178def destroy_test_db(old_database_name, old_databases, verbosity=1):
    152179    # If the database wants to drop the test DB itself, let it
    153180    creation_module = get_creation_module()
    154181    if hasattr(creation_module, "destroy_test_db"):
    155182        creation_module.destroy_test_db(settings, connection, backend, old_database_name, verbosity)
    156183        return
    157    
    158184    # Unless we're using SQLite, remove the test database to clean up after
    159185    # ourselves. Connect to the previous database (not the test database)
    160186    # to do so, because it's not allowed to delete a database while being
    161187    # connected to it.
    162188    if verbosity >= 1:
    163189        print "Destroying test database..."
     190
    164191    connection.close()
     192    for cnx in connections.keys():
     193        connections[cnx].close()
     194    connections.reset()
     195   
    165196    TEST_DATABASE_NAME = settings.DATABASE_NAME
     197    if verbosity >= 2:
     198        print "Closed connections to %s" % TEST_DATABASE_NAME
    166199    settings.DATABASE_NAME = old_database_name
    167 
     200   
    168201    if settings.DATABASE_ENGINE != "sqlite3":
     202        settings.OTHER_DATABASES = old_databases
     203        for cnx in connections.keys():
     204            try:
     205                connections[cnx].connection.cursor()
     206            except (KeyboardInterrupt, SystemExit):
     207                raise
     208            except:
     209                pass
    169210        cursor = connection.cursor()
    170211        _set_autocommit(connection)
    171212        time.sleep(1) # To avoid "database is being accessed by other users" errors.
  • django/http/__init__.py

    === django/http/__init__.py
    ==================================================================
     
    224224        content = ''.join(self._container)
    225225        if isinstance(content, unicode):
    226226            content = content.encode(self._charset)
     227
     228        # If self._container was an iterator, we have just exhausted it, so we
     229        # need to save the results for anything else that needs access
     230        if not self._is_string:
     231            self._container = [content]
     232            self._is_string = True
    227233        return content
    228234
    229235    def _set_content(self, value):
     
    233239    content = property(_get_content, _set_content)
    234240
    235241    def __iter__(self):
    236         self._iterator = self._container.__iter__()
    237         return self
     242        for chunk in self._container:
     243            if isinstance(chunk, unicode):
     244                chunk = chunk.encode(self._charset)
     245            yield chunk
    238246
    239     def next(self):
    240         chunk = self._iterator.next()
    241         if isinstance(chunk, unicode):
    242             chunk = chunk.encode(self._charset)
    243         return chunk
    244 
    245247    def close(self):
    246248        if hasattr(self._container, 'close'):
    247249            self._container.close()
  • django/oldforms/__init__.py

    === django/oldforms/__init__.py
    ==================================================================
     
    309309        return data
    310310    html2python = staticmethod(html2python)
    311311
     312    def iter_render(self, data):
     313        # this even needed?
     314        return (self.render(data),)
     315
    312316    def render(self, data):
    313317        raise NotImplementedError
    314318
  • django/db/models/base.py

    === django/db/models/base.py
    ==================================================================
     
    66from django.db.models.fields.related import OneToOneRel, ManyToOneRel
    77from django.db.models.query import delete_objects
    88from django.db.models.options import Options, AdminOptions
    9 from django.db import connection, backend, transaction
     9from django.db import transaction
    1010from django.db.models import signals
    1111from django.db.models.loading import register_models, get_model
    1212from django.dispatch import dispatcher
     
    2222    "Metaclass for all models"
    2323    def __new__(cls, name, bases, attrs):
    2424        # If this isn't a subclass of Model, don't do anything special.
     25        print "\n\n" + "*"*40
     26        print "ModelBase Called with name: %s and attrs:" % name
     27        print "\n".join(["%s => %s" % (k,v) for k, v in attrs.items()])
    2528        try:
    2629            if not filter(lambda b: issubclass(b, Model), bases):
    2730                return super(ModelBase, cls).__new__(cls, name, bases, attrs)
     
    201204    def save(self):
    202205        dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self)
    203206
     207        db = self.__class__._default_manager.db
     208        connection = db.connection
     209        backend = db.backend
     210        qn = backend.quote_name
    204211        non_pks = [f for f in self._meta.fields if not f.primary_key]
    205212        cursor = connection.cursor()
    206213
     
    211218        if pk_set:
    212219            # Determine whether a record with the primary key already exists.
    213220            cursor.execute("SELECT COUNT(*) FROM %s WHERE %s=%%s" % \
    214                 (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)),
     221                (qn(self._meta.db_table), qn(self._meta.pk.column)),
    215222                self._meta.pk.get_db_prep_lookup('exact', pk_val))
    216223            # If it does already exist, do an UPDATE.
    217224            if cursor.fetchone()[0] > 0:
    218225                db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks]
    219226                if db_values:
    220227                    cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
    221                         (backend.quote_name(self._meta.db_table),
    222                         ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
    223                         backend.quote_name(self._meta.pk.column)),
     228                        (qn(self._meta.db_table),
     229                        ','.join(['%s=%%s' % qn(f.column) for f in non_pks]),
     230                        qn(self._meta.pk.column)),
    224231                        db_values + self._meta.pk.get_db_prep_lookup('exact', pk_val))
    225232            else:
    226233                record_exists = False
    227234        if not pk_set or not record_exists:
    228             field_names = [backend.quote_name(f.column) for f in self._meta.fields if not isinstance(f, AutoField)]
     235            field_names = [qn(f.column) for f in self._meta.fields if not isinstance(f, AutoField)]
    229236            db_values = [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]
    230237            # If the PK has been manually set, respect that.
    231238            if pk_set:
     
    233240                db_values += [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
    234241            placeholders = ['%s'] * len(field_names)
    235242            if self._meta.order_with_respect_to:
    236                 field_names.append(backend.quote_name('_order'))
     243                field_names.append(qn('_order'))
    237244                # TODO: This assumes the database supports subqueries.
    238245                placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \
    239                     (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column)))
     246                    (qn(self._meta.db_table), qn(self._meta.order_with_respect_to.column)))
    240247                db_values.append(getattr(self, self._meta.order_with_respect_to.attname))
    241248            if db_values:
    242249                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
    243                     (backend.quote_name(self._meta.db_table), ','.join(field_names),
     250                    (qn(self._meta.db_table), ','.join(field_names),
    244251                    ','.join(placeholders)), db_values)
    245252            else:
    246253                # Create a new record with defaults for everything.
    247254                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" %
    248                     (backend.quote_name(self._meta.db_table),
    249                      backend.quote_name(self._meta.pk.column),
     255                    (qn(self._meta.db_table),
     256                     qn(self._meta.pk.column),
    250257                     backend.get_pk_default_value()))
    251258            if self._meta.has_auto_field and not pk_set:
    252259                setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column))
    253         transaction.commit_unless_managed()
     260        transaction.commit_unless_managed([connection])
    254261
    255262        # Run any post-save hooks.
    256263        dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self)
     
    321328        return dict(field.choices).get(value, value)
    322329
    323330    def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
     331        qn = self._default_manager.db.backend.quote_name
    324332        op = is_next and '>' or '<'
    325333        where = '(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \
    326             (backend.quote_name(field.column), op, backend.quote_name(field.column),
    327             backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column), op)
     334            (qn(field.column), op, qn(field.column),
     335            qn(self._meta.db_table), qn(self._meta.pk.column), op)
    328336        param = str(getattr(self, field.attname))
    329337        q = self.__class__._default_manager.filter(**kwargs).order_by((not is_next and '-' or '') + field.name, (not is_next and '-' or '') + self._meta.pk.name)
    330338        q._where.append(where)
     
    335343            raise self.DoesNotExist, "%s matching query does not exist." % self.__class__._meta.object_name
    336344
    337345    def _get_next_or_previous_in_order(self, is_next):
     346        qn = self._default_manager.db.backend.quote_name
     347
    338348        cachename = "__%s_order_cache" % is_next
    339349        if not hasattr(self, cachename):
    340350            op = is_next and '>' or '<'
    341351            order_field = self._meta.order_with_respect_to
    342352            where = ['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \
    343                 (backend.quote_name('_order'), op, backend.quote_name('_order'),
    344                 backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)),
    345                 '%s=%%s' % backend.quote_name(order_field.column)]
     353                (qn('_order'), op, qn('_order'),
     354                qn(self._meta.db_table), qn(self._meta.pk.column)),
     355                '%s=%%s' % qn(order_field.column)]
    346356            params = [self._get_pk_val(), getattr(self, order_field.attname)]
    347357            obj = self._default_manager.order_by('_order').extra(where=where, params=params)[:1].get()
    348358            setattr(self, cachename, obj)
     
    424434# ORDERING METHODS #########################
    425435
    426436def method_set_order(ordered_obj, self, id_list):
     437    db = ordered_obj._default_manager.db
     438    connection = db.connection
     439    qn = db.backend.quote_name
    427440    cursor = connection.cursor()
    428441    # Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s"
    429442    sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \
    430         (backend.quote_name(ordered_obj._meta.db_table), backend.quote_name('_order'),
    431         backend.quote_name(ordered_obj._meta.order_with_respect_to.column),
    432         backend.quote_name(ordered_obj._meta.pk.column))
     443        (qn(ordered_obj._meta.db_table), qn('_order'),
     444        qn(ordered_obj._meta.order_with_respect_to.column),
     445        qn(ordered_obj._meta.pk.column))
    433446    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
    434447    cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)])
    435     transaction.commit_unless_managed()
     448    transaction.commit_unless_managed([connection])
    436449
    437450def method_get_order(ordered_obj, self):
     451    db = ordered_obj._default_manager.db
     452    connection = db.connection
     453    qn = db.backend.quote_name
    438454    cursor = connection.cursor()
    439455    # Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order"
    440456    sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \
    441         (backend.quote_name(ordered_obj._meta.pk.column),
    442         backend.quote_name(ordered_obj._meta.db_table),
    443         backend.quote_name(ordered_obj._meta.order_with_respect_to.column),
    444         backend.quote_name('_order'))
     457        (qn(ordered_obj._meta.pk.column),
     458        qn(ordered_obj._meta.db_table),
     459        qn(ordered_obj._meta.order_with_respect_to.column),
     460        qn('_order'))
    445461    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
    446462    cursor.execute(sql, [rel_val])
    447463    return [r[0] for r in cursor.fetchall()]
  • django/db/models/manager.py

    === django/db/models/manager.py
    ==================================================================
     
     1from django.db import ConnectionInfoDescriptor
    12from django.db.models.query import QuerySet, EmptyQuerySet
    23from django.dispatch import dispatcher
    3 from django.db.models import signals
     4from django.db.models import signals, get_apps, get_models
    45from django.db.models.fields import FieldDoesNotExist
    56
     7try:
     8    # Only exists in Python 2.4+
     9    from threading import local
     10except ImportError:
     11    # Import copy of _thread_local.py from Python 2.4
     12    from django.utils._threading_local import local
     13
    614# Size of each "chunk" for get_iterator calls.
    715# Larger values are slightly faster at the expense of more storage space.
    816GET_ITERATOR_CHUNK_SIZE = 100
     
    1725        except FieldDoesNotExist:
    1826            pass
    1927        cls.add_to_class('objects', Manager())
    20 
     28    elif cls._default_manager.model != cls:
     29        # cls is an inherited model; don't want the parent manager
     30        cls.add_to_class('objects', Manager())
    2131dispatcher.connect(ensure_default_manager, signal=signals.class_prepared)
    2232
     33
     34
    2335class Manager(object):
    2436    # Tracks each time a Manager instance is created. Used to retain order.
    2537    creation_counter = 0
    26 
     38    db = ConnectionInfoDescriptor()
     39   
    2740    def __init__(self):
    2841        super(Manager, self).__init__()
    2942        # Increase the creation counter, and save our local copy.
     
    3548        # TODO: Use weakref because of possible memory leak / circular reference.
    3649        self.model = model
    3750        setattr(model, name, ManagerDescriptor(self))
    38         if not hasattr(model, '_default_manager') or self.creation_counter < model._default_manager.creation_counter:
     51        if not hasattr(model, '_default_manager') \
     52            or self.creation_counter < model._default_manager.creation_counter \
     53            or model._default_manager.model != model:
    3954            model._default_manager = self
    40 
     55       
    4156    #######################
    4257    # PROXIES TO QUERYSET #
    4358    #######################
     
    105120    def values(self, *args, **kwargs):
    106121        return self.get_query_set().values(*args, **kwargs)
    107122
     123    #######################
     124    # SCHEMA MANIPULATION #
     125    #######################
     126
     127    def install(self, initial_data=False, pending=None):
     128        """Install my model's table, indexes and (if requested) initial data.
     129
     130        Returns a dict of pending statements, keyed by the model that
     131        needs to be created before the statements can be executed.
     132        (Pending statements are those that could not yet be executed,
     133        such as foreign key constraints for tables that don't exist at
     134        install time.)
     135        """
     136        if pending is None:
     137            pending = {}
     138        builder = self.db.get_creation_module().builder
     139        run, pending = builder.get_create_table(self.model, pending=pending)
     140        run += builder.get_create_indexes(self.model)
     141        many_many = builder.get_create_many_to_many(self.model)
     142
     143        for statement in run:
     144            statement.execute()
     145        for klass, statements in many_many.items():
     146            if klass in builder.models_already_seen:
     147                for statement in statements:
     148                    statement.execute()
     149            else:
     150                pending.setdefault(klass, []).extend(statements)
     151        if initial_data:
     152            self.load_initial_data()
     153        return pending
     154
     155    def get_pending(self, rel_class, f):
     156        """Get list pending statement relating my model to rel_class via
     157        field f
     158        """
     159        builder = self.db.get_creation_module().builder
     160        return builder.get_ref_sql(self.model, rel_class, f)
     161
     162    def load_initial_data(self):
     163        """Install initial data for model in db, Returns statements executed.
     164        """
     165        builder = self.db.get_creation_module().builder
     166        statements = builder.get_initialdata(self.model)
     167        for statement in statements:
     168            statement.execute()
     169        return statements
     170       
     171    def get_installed_models(self, table_list):
     172        """Get list of models installed, given a list of tables.
     173        """
     174        all_models = []
     175        for app in get_apps():
     176            for model in get_models(app):
     177                all_models.append(model)
     178        return set([m for m in all_models
     179                    if m._meta.db_table in table_list])
     180
     181    def get_table_list(self):
     182        """Get list of tables accessible via my model's connection.
     183        """
     184        builder = self.db.get_creation_module().builder
     185        return builder.get_table_list(self.db)
     186   
    108187class ManagerDescriptor(object):
    109188    # This class ensures managers aren't accessible via model instances.
    110189    # For example, Poll.objects works, but poll_obj.objects raises AttributeError.
     
    115194        if instance != None:
    116195            raise AttributeError, "Manager isn't accessible via %s instances" % type.__name__
    117196        return self.manager
     197
  • django/db/models/options.py

    === django/db/models/options.py
    ==================================================================
     
    11from django.conf import settings
     2from django.db import connection_info, connections
    23from django.db.models.related import RelatedObject
    34from django.db.models.fields.related import ManyToManyRel
    45from django.db.models.fields import AutoField, FieldDoesNotExist
     
    78from django.db.models import Manager
    89from bisect import bisect
    910import re
     11import weakref
    1012
    1113# Calculate the verbose_name by converting from InitialCaps to "lowercase with spaces".
    1214get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip()
     
    7981            self.db_table = truncate_name(self.db_table,
    8082                                          backend.get_max_name_length())
    8183
     84        # Keep a weakref to my model, for access to managers and such
     85        self._model = weakref.ref(model)
     86
    8287    def add_field(self, field):
    8388        # Insert the given field in the order in which it was created, using
    8489        # the "creation_counter" attribute of the field.
     
    105110                return f
    106111        raise FieldDoesNotExist, '%s has no field named %r' % (self.object_name, name)
    107112
     113    def get_default_manager(self):
     114        model = self._model()
     115        if model is None:
     116            raise ReferenceError("Model no longer available in %s" % self)
     117        return model._default_manager
     118
    108119    def get_order_sql(self, table_prefix=''):
    109120        "Returns the full 'ORDER BY' clause for this object, according to self.ordering."
    110121        if not self.ordering: return ''
  • django/db/models/loading.py

    === django/db/models/loading.py
    ==================================================================
     
    1212_app_models = {} # Dictionary of models against app label
    1313                 # Each value is a dictionary of model name: model class
    1414                 # Applabel and Model entry exists in cache when individual model is loaded.
     15_app_model_order = {} # Dictionary of models against app label
     16                      # Each value is a list of model names, in the order in
     17                      # which the models were created
    1518_app_errors = {} # Dictionary of errors that were experienced when loading the INSTALLED_APPS
    1619                 # Key is the app_name of the model, value is the exception that was raised
    1720                 # during model loading.
     
    6164    get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
    6265    return _app_errors
    6366
    64 def get_models(app_mod=None):
     67def get_models(app_mod=None, creation_order=False):
    6568    """
    6669    Given a module containing models, returns a list of the models. Otherwise
    6770    returns a list of all installed models.
    6871    """
    6972    app_list = get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
    7073    if app_mod:
    71         return _app_models.get(app_mod.__name__.split('.')[-2], {}).values()
     74        app_label = app_mod.__name__.split('.')[-2]
     75        app_models = _app_models.get(app_label, {})
     76        if creation_order:
     77            return [ app_models[name]
     78                     for name in _app_model_order.get(app_label, []) ]
     79        return app_models.values()
    7280    else:
    7381        model_list = []
    7482        for app_mod in app_list:
  • django/db/models/fields/__init__.py

    === django/db/models/fields/__init__.py
    ==================================================================
     
    536536                except ValueError:
    537537                    raise validators.ValidationError, gettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.')
    538538
    539     def get_db_prep_save(self, value):
    540         # Casts dates into string format for entry into database.
     539    def pre_save(self, model_instance, add):
     540        value = super(DateField, self).pre_save(model_instance, add)
    541541        if value is not None:
    542542            # MySQL will throw a warning if microseconds are given, because it
    543543            # doesn't support microseconds.
     544            settings = model_instance._default_manager.db.connection.settings
    544545            if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
    545546                value = value.replace(microsecond=0)
     547        return value
     548
     549    def get_db_prep_save(self, value):
     550        # Casts dates into string format for entry into database.
     551        if value is not None:
    546552            value = str(value)
    547553        return Field.get_db_prep_save(self, value)
    548554
     
    909915        if value is not None:
    910916            # MySQL will throw a warning if microseconds are given, because it
    911917            # doesn't support microseconds.
     918            settings = model_instance._default_manager.db.connection.settings
    912919            if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
    913920                value = value.replace(microsecond=0)
    914921            if settings.DATABASE_ENGINE == 'oracle':
  • django/db/models/fields/related.py

    === django/db/models/fields/related.py
    ==================================================================
     
    1 from django.db import backend, transaction
     1from django.db import transaction
    22from django.db.models import signals, get_model
    33from django.db.models.fields import AutoField, Field, IntegerField, get_ul_class
    44from django.db.models.related import RelatedObject
     
    318318            # source_col_name: the PK colname in join_table for the source object
    319319            # target_col_name: the PK colname in join_table for the target object
    320320            # *objs - objects to add. Either object instances, or primary keys of object instances.
    321             from django.db import connection
     321            connection = self.model._default_manager.db.connection
    322322
    323323            # If there aren't any objects, there is nothing to do.
    324324            if objs:
     
    343343                    cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
    344344                        (self.join_table, source_col_name, target_col_name),
    345345                        [self._pk_val, obj_id])
    346                 transaction.commit_unless_managed()
     346            transaction.commit_unless_managed(connection)
    347347
    348348        def _remove_items(self, source_col_name, target_col_name, *objs):
    349349            # source_col_name: the PK colname in join_table for the source object
    350350            # target_col_name: the PK colname in join_table for the target object
    351351            # *objs - objects to remove
    352             from django.db import connection
     352            connection = self.model._default_manager.db.connection
    353353
    354354            # If there aren't any objects, there is nothing to do.
    355355            if objs:
     
    366366                    (self.join_table, source_col_name,
    367367                    target_col_name, ",".join(['%s'] * len(old_ids))),
    368368                    [self._pk_val] + list(old_ids))
    369                 transaction.commit_unless_managed()
     369            transaction.commit_unless_managed(connection)
    370370
    371371        def _clear_items(self, source_col_name):
    372372            # source_col_name: the PK colname in join_table for the source object
    373             from django.db import connection
     373            connection = self.model._default_manager.db.connection
    374374            cursor = connection.cursor()
    375375            cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
    376376                (self.join_table, source_col_name),
    377377                [self._pk_val])
    378             transaction.commit_unless_managed()
     378            transaction.commit_unless_managed(connection)
    379379
    380380    return ManyRelatedManager
    381381
     
    399399        superclass = rel_model._default_manager.__class__
    400400        RelatedManager = create_many_related_manager(superclass)
    401401
    402         qn = backend.quote_name
     402        qn = rel_model._default_manager.db.backend.quote_name
    403403        manager = RelatedManager(
    404404            model=rel_model,
    405405            core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()},
     
    440440        superclass = rel_model._default_manager.__class__
    441441        RelatedManager = create_many_related_manager(superclass)
    442442
    443         qn = backend.quote_name
     443        qn = rel_model._default_manager.db.backend.quote_name
    444444        manager = RelatedManager(
    445445            model=rel_model,
    446446            core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()},
  • django/db/models/query.py

    === django/db/models/query.py
    ==================================================================
     
    182182        # self._select is a dictionary, and dictionaries' key order is
    183183        # undefined, so we convert it to a list of tuples.
    184184        extra_select = self._select.items()
    185 
    186         cursor = connection.cursor()
     185        cursor = self.model._default_manager.db.connection.cursor()
    187186        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
    188187
    189188        fill_cache = self._select_related
     
    217216        """
    218217        if self._result_cache is not None:
    219218            return len(self._result_cache)
    220 
     219        #from multi-db
     220        db = self.model._default_manager.db
     221        backend = db.backend
     222        connection = db.connection
     223       
    221224        counter = self._clone()
    222225        counter._order_by = ()
    223226        counter._select_related = False
     
    304307        Returns a dictionary mapping each of the given IDs to the object with
    305308        that ID.
    306309        """
     310        backend = self.model._default_manager.db.backend
    307311        assert self._limit is None and self._offset is None, \
    308312                "Cannot use 'limit' or 'offset' with in_bulk"
    309313        assert isinstance(id_list, (tuple,  list)), "in_bulk() must be provided with a list of IDs."
     
    481485
    482486    def _get_sql_clause(self):
    483487        opts = self.model._meta
    484 
     488        backend = self.model._default_manager.db.backend
     489        qn = backend.quote_name
    485490        # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
    486         select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields]
     491        select = ["%s.%s" % (qn(opts.db_table), qn(f.column))
     492                  for f in opts.fields]
    487493        tables = [quote_only_if_word(t) for t in self._tables]
    488494        joins = SortedDict()
    489495        where = self._where[:]
     
    504510
    505511        # Add any additional SELECTs.
    506512        if self._select:
    507             select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
     513            select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0]))
     514                           for s in self._select.items()])
    508515
    509516        # Start composing the body of the SQL statement.
    510         sql = [" FROM", backend.quote_name(opts.db_table)]
     517        sql = [" FROM", qn(opts.db_table)]
    511518
    512519        # Compose the join dictionary into SQL describing the joins.
    513520        if joins:
     
    540547                    order = "ASC"
    541548                if "." in col_name:
    542549                    table_prefix, col_name = col_name.split('.', 1)
    543                     table_prefix = backend.quote_name(table_prefix) + '.'
     550                    table_prefix = qn(table_prefix) + '.'
    544551                else:
    545552                    # Use the database table as a column prefix if it wasn't given,
    546553                    # and if the requested column isn't a custom SELECT.
    547554                    if "." not in col_name and col_name not in (self._select or ()):
    548                         table_prefix = backend.quote_name(opts.db_table) + '.'
     555                        table_prefix = qn(opts.db_table) + '.'
    549556                    else:
    550557                        table_prefix = ''
    551                 order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order))
     558                order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order))
    552559        if order_by:
    553560            sql.append("ORDER BY " + ", ".join(order_by))
    554561
     
    597604
    598605        columns = [f.column for f in fields]
    599606        select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
     607           
     608        #from multi-db
     609        db = self.model._default_manager.db
     610        backend = db.backend
     611        qn = backend.quote_name
     612        connection = db.connection
     613
    600614        # Add any additional SELECTs.
    601615        if self._select:
    602616            select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
    603617
    604618        cursor = connection.cursor()
     619        select = ['%s.%s' % (qn(self.model._meta.db_table), qn(c))
     620                  for c in columns]
    605621        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
    606622
    607623        has_resolve_columns = hasattr(self, 'resolve_columns')
     
    623639    def iterator(self):
    624640        from django.db.backends.util import typecast_timestamp
    625641        from django.db.models.fields import DateTimeField
     642        db = self.model._default_manager.db
     643        backend = db.backend
     644        qn = backend.quote_name
     645        connection = db.connection
     646       
    626647        self._order_by = () # Clear this because it'll mess things up otherwise.
    627648        if self._field.null:
    628649            self._where.append('%s.%s IS NOT NULL' % \
    629                 (backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
     650                (qn(self.model._meta.db_table), qn(self._field.column)))
     651
    630652        try:
    631653            select, sql, params = self._get_sql_clause()
    632654        except EmptyResultSet:
    633655            raise StopIteration
    634656
    635         table_name = backend.quote_name(self.model._meta.db_table)
    636         field_name = backend.quote_name(self._field.column)
     657        table_name = qn(self.model._meta.db_table)
     658        field_name = qn(self._field.column)
    637659
    638660        if backend.allows_group_by_ordinal:
    639661            group_by = '1'
     
    768790            return SortedDict(), [], []
    769791        return joins, where2, params
    770792
    771 def get_where_clause(lookup_type, table_prefix, field_name, value):
     793def get_where_clause(opts, lookup_type, table_prefix, field_name, value):
     794    backend = opts.get_default_manager().db.backend
     795    qn = backend.quote_name
     796   
    772797    if table_prefix.endswith('.'):
    773         table_prefix = backend.quote_name(table_prefix[:-1])+'.'
    774     field_name = backend.quote_name(field_name)
     798        table_prefix = qn(table_prefix[:-1])+'.'
     799    field_name = qn(field_name)
    775800    if type(value) == datetime.datetime and backend.get_datetime_cast_sql():
    776801        cast_sql = backend.get_datetime_cast_sql()
    777802    else:
     
    832857    Helper function that recursively populates the select, tables and where (in
    833858    place) for select_related queries.
    834859    """
     860    qn = opts.get_default_manager().db.backend.quote_name
    835861
    836862    # If we've got a max_depth set and we've exceeded that depth, bail now.
    837863    if max_depth and cur_depth > max_depth:
    838864        return None
    839865
    840     qn = backend.quote_name
    841866    for f in opts.fields:
    842867        if f.rel and not f.null:
    843868            db_table = f.rel.to._meta.db_table
     
    935960    return choices
    936961
    937962def lookup_inner(path, lookup_type, value, opts, table, column):
    938     qn = backend.quote_name
    939963    joins, where, params = SortedDict(), [], []
    940964    current_opts = opts
    941965    current_table = table
    942966    current_column = column
    943967    intermediate_table = None
    944968    join_required = False
     969    db = current_opts.get_default_manager().db
     970    backend = db.backend
     971    connection = db.connection
     972    qn = backend.quote_name
    945973
    946974    name = path.pop(0)
    947975    # Has the primary key been requested? If so, expand it out
     
    10921120            # Last query term was a normal field.
    10931121            column = field.column
    10941122
    1095         where.append(get_where_clause(lookup_type, current_table + '.', column, value))
     1123        where.append(get_where_clause(current_opts, lookup_type, current_table + '.', column, value))
    10961124        params.extend(field.get_db_prep_lookup(lookup_type, value))
    10971125
    10981126    return joins, where, params
    10991127
    11001128def delete_objects(seen_objs):
    11011129    "Iterate through a list of seen classes, and remove any instances that are referred to"
    1102     qn = backend.quote_name
    11031130    ordered_classes = seen_objs.keys()
    11041131    ordered_classes.reverse()
    11051132
    1106     cursor = connection.cursor()
    1107 
    11081133    for cls in ordered_classes:
     1134        db = cls._default_manager.db
     1135        backend = db.backend
     1136        connection = db.connection
     1137        cursor = connection.cursor()
     1138        qn = backend.quote_name
     1139       
    11091140        seen_objs[cls] = seen_objs[cls].items()
    11101141        seen_objs[cls].sort()
    11111142
     
    11441175                        pk_list[offset:offset+GET_ITERATOR_CHUNK_SIZE])
    11451176
    11461177    # Now delete the actual data
     1178    dirty_conns = []
    11471179    for cls in ordered_classes:
     1180
     1181        db = cls._default_manager.db
     1182        backend = db.backend
     1183        connection = db.connection
     1184        qn = backend.quote_name
     1185        cursor = connection.cursor()
     1186        if connection not in dirty_conns:
     1187            dirty_conns.append(connection)
     1188           
    11481189        seen_objs[cls].reverse()
    11491190        pk_list = [pk for pk,instance in seen_objs[cls]]
    11501191        for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
     
    11631204            setattr(instance, cls._meta.pk.attname, None)
    11641205            dispatcher.send(signal=signals.post_delete, sender=cls, instance=instance)
    11651206
    1166     transaction.commit_unless_managed()
     1207    transaction.commit_unless_managed(dirty_conns)
  • django/db/__init__.py

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

    === django/db/backends/ado_mssql/base.py
    ==================================================================
     
    4848    return res
    4949Database.convertVariantToPython = variantToPython
    5050
    51 try:
    52     # Only exists in Python 2.4+
    53     from threading import local
    54 except ImportError:
    55     # Import copy of _thread_local.py from Python 2.4
    56     from django.utils._threading_local import local
    57 
    58 class DatabaseWrapper(local):
    59     def __init__(self, **kwargs):
     51class DatabaseWrapper(object):
     52    def __init__(self, settings):
     53        self.settings = settings
     54        self.options = settings.DATABASE_OPTIONS
    6055        self.connection = None
    6156        self.queries = []
    6257
    6358    def cursor(self):
    64         from django.conf import settings
     59        settings = self.settings
    6560        if self.connection is None:
    6661            if settings.DATABASE_NAME == '' or settings.DATABASE_USER == '':
    6762                from django.core.exceptions import ImproperlyConfigured
     
    9590needs_datetime_string_cast = True
    9691needs_upper_for_iops = False
    9792supports_constraints = True
     93supports_compound_statements = True
    9894supports_tablespaces = True
    9995uses_case_insensitive_names = False
    10096
  • django/db/backends/ado_mssql/client.py

    === django/db/backends/ado_mssql/client.py
    ==================================================================
     
    1 def runshell():
     1def runshell(settings):
    22    raise NotImplementedError
  • django/db/backends/ado_mssql/creation.py

    === django/db/backends/ado_mssql/creation.py
    ==================================================================
     
     1from django.db.backends.ansi import sql
     2builder = sql.SchemaBuilder()
     3
    14DATA_TYPES = {
    25    'AutoField':         'int IDENTITY (1, 1)',
    36    'BooleanField':      'bit',
  • django/db/backends/postgresql/base.py

    === django/db/backends/postgresql/base.py
    ==================================================================
     
    1414DatabaseError = Database.DatabaseError
    1515IntegrityError = Database.IntegrityError
    1616
    17 try:
    18     # Only exists in Python 2.4+
    19     from threading import local
    20 except ImportError:
    21     # Import copy of _thread_local.py from Python 2.4
    22     from django.utils._threading_local import local
    23 
     17class DatabaseWrapper(object):
     18    def __init__(self, settings):
     19        self.settings = settings
    2420def smart_basestring(s, charset):
    2521    if isinstance(s, unicode):
    2622        return s.encode(charset)
     
    5551
    5652postgres_version = None
    5753
    58 class DatabaseWrapper(local):
    59     def __init__(self, **kwargs):
    6054        self.connection = None
    6155        self.queries = []
    62         self.options = kwargs
     56        self.options = settings.DATABASE_OPTIONS
    6357
    6458    def cursor(self):
    65         from django.conf import settings
     59        settings = self.settings
    6660        set_tz = False
    6761        if self.connection is None:
    6862            set_tz = True
     
    111105needs_datetime_string_cast = True
    112106needs_upper_for_iops = False
    113107supports_constraints = True
     108supports_compound_statements = True
    114109supports_tablespaces = False
    115110uses_case_insensitive_names = False
    116111
  • django/db/backends/postgresql/client.py

    === django/db/backends/postgresql/client.py
    ==================================================================
     
    1 from django.conf import settings
    21import os
    32
    4 def runshell():
     3def runshell(settings):
    54    args = ['psql']
    65    if settings.DATABASE_USER:
    76        args += ["-U", settings.DATABASE_USER]
  • django/db/backends/postgresql/sql.py

    === django/db/backends/postgresql/sql.py
    ==================================================================
     
     1from django.db import models
     2from django.db.backends.ansi.sql import BoundStatement, SchemaBuilder, \
     3    default_style
     4
     5class PgSchemaBuilder(SchemaBuilder):
     6    """SchemaBuilder for postgres. Implements an additional method that
     7    outputs SQL statements to reset the sequence(s) for a model.
     8    """
     9    def get_sequence_reset(self, model, style=None):
     10        """Get sequence reset sql for a model.
     11        """
     12        if style is None:
     13            style=default_style
     14        for f in model._meta.fields:
     15            output = []
     16            db = model._default_manager.db
     17            connection = db.connection
     18            qn = db.backend.quote_name
     19            if isinstance(f, models.AutoField):
     20                output.append(BoundStatement(
     21                        "%s setval('%s', (%s max(%s) %s %s));" % \
     22                        (style.SQL_KEYWORD('SELECT'),
     23                         style.SQL_FIELD('%s_%s_seq' %
     24                                         (model._meta.db_table, f.column)),
     25                         style.SQL_KEYWORD('SELECT'),
     26                         style.SQL_FIELD(qn(f.column)),
     27                         style.SQL_KEYWORD('FROM'),
     28                         style.SQL_TABLE(qn(model._meta.db_table))),
     29                        connection))
     30                break # Only one AutoField is allowed per model, so don't bother continuing.
     31        for f in model._meta.many_to_many:
     32            output.append(
     33                BoundStatement("%s setval('%s', (%s max(%s) %s %s));" % \
     34                               (style.SQL_KEYWORD('SELECT'),
     35                                style.SQL_FIELD('%s_id_seq' % f.m2m_db_table()),
     36                                style.SQL_KEYWORD('SELECT'),
     37                                style.SQL_FIELD(qn('id')),
     38                                style.SQL_KEYWORD('FROM'),
     39                                style.SQL_TABLE(f.m2m_db_table())),
     40                               connection))
     41        return output
  • django/db/backends/postgresql/creation.py

    === django/db/backends/postgresql/creation.py
    ==================================================================
     
     1from django.db.backends.postgresql import sql
     2builder = sql.PgSchemaBuilder()
     3
    14# This dictionary maps Field objects to their associated PostgreSQL column
    25# types, as strings. Column-type strings can contain format strings; they'll
    36# be interpolated against the values of Field.__dict__ before being output.
  • django/db/backends/sqlite3/base.py

    === django/db/backends/sqlite3/base.py
    ==================================================================
     
    5050    from django.utils._threading_local import local
    5151
    5252class DatabaseWrapper(local):
    53     def __init__(self, **kwargs):
     53    def __init__(self, settings):
     54        self.settings = settings
    5455        self.connection = None
    5556        self.queries = []
    56         self.options = kwargs
     57        self.options = settings.DATABASE_OPTIONS
    5758
    5859    def cursor(self):
    59         from django.conf import settings
     60        settings = self.settings
    6061        if self.connection is None:
    6162            kwargs = {
    6263                'database': settings.DATABASE_NAME,
     
    114115needs_datetime_string_cast = True
    115116needs_upper_for_iops = False
    116117supports_constraints = False
     118supports_compound_statements = False
    117119supports_tablespaces = False
    118120uses_case_insensitive_names = False
    119121
  • django/db/backends/sqlite3/client.py

    === django/db/backends/sqlite3/client.py
    ==================================================================
     
    1 from django.conf import settings
    21import os
    32
    4 def runshell():
     3def runshell(settings):
    54    args = ['', settings.DATABASE_NAME]
    65    os.execvp('sqlite3', args)
  • django/db/backends/sqlite3/creation.py

    === django/db/backends/sqlite3/creation.py
    ==================================================================
     
     1from django.db.backends.ansi import sql
     2builder = sql.SchemaBuilder()
     3
    14# SQLite doesn't actually support most of these types, but it "does the right
    25# thing" given more verbose field definitions, so leave them as is so that
    36# schema inspection is more useful.
  • django/db/backends/mysql/base.py

    === django/db/backends/mysql/base.py
    ==================================================================
     
    5353# standard util.CursorDebugWrapper can be used. Also, using sql_mode
    5454# TRADITIONAL will automatically cause most warnings to be treated as errors.
    5555
    56 try:
    57     # Only exists in Python 2.4+
    58     from threading import local
    59 except ImportError:
    60     # Import copy of _thread_local.py from Python 2.4
    61     from django.utils._threading_local import local
    6256
    63 class DatabaseWrapper(local):
    64     def __init__(self, **kwargs):
     57class DatabaseWrapper(object):
     58    def __init__(self, settings):
     59        self.settings = settings
    6560        self.connection = None
    6661        self.queries = []
    6762        self.server_version = None
    68         self.options = kwargs
     63        self.options = settings.DATABASE_OPTIONS
    6964
    7065    def _valid_connection(self):
    7166        if self.connection is not None:
     
    7873        return False
    7974
    8075    def cursor(self):
    81         from django.conf import settings
     76        settings = self.settings
    8277        from warnings import filterwarnings
    8378        if not self._valid_connection():
    8479            kwargs = {
     
    140135needs_datetime_string_cast = True     # MySQLdb requires a typecast for dates
    141136needs_upper_for_iops = False
    142137supports_constraints = True
     138supports_compound_statements = True
    143139supports_tablespaces = False
    144140uses_case_insensitive_names = False
    145141
  • django/db/backends/mysql/client.py

    === django/db/backends/mysql/client.py
    ==================================================================
     
    1 from django.conf import settings
    21import os
    32
    4 def runshell():
     3def runshell(settings):
    54    args = ['']
    65    db = settings.DATABASE_OPTIONS.get('db', settings.DATABASE_NAME)
    76    user = settings.DATABASE_OPTIONS.get('user', settings.DATABASE_USER)
  • django/db/backends/mysql/creation.py

    === django/db/backends/mysql/creation.py
    ==================================================================
     
     1from django.db.backends.ansi import sql
     2builder = sql.SchemaBuilder()
     3
    14# This dictionary maps Field objects to their associated MySQL column
    25# types, as strings. Column-type strings can contain format strings; they'll
    36# be interpolated against the values of Field.__dict__ before being output.
  • django/db/backends/oracle/base.py

    === django/db/backends/oracle/base.py
    ==================================================================
     
    1818DatabaseError = Database.Error
    1919IntegrityError = Database.IntegrityError
    2020
    21 try:
    22     # Only exists in Python 2.4+
    23     from threading import local
    24 except ImportError:
    25     # Import copy of _thread_local.py from Python 2.4
    26     from django.utils._threading_local import local
    27 
    28 class DatabaseWrapper(local):
    29     def __init__(self, **kwargs):
     21class DatabaseWrapper(object):
     22    def __init__(self, settings):
     23        self.settings = settings
    3024        self.connection = None
    3125        self.queries = []
    32         self.options = kwargs
     26        self.options = settings.DATABASE_OPTIONS
    3327
    3428    def _valid_connection(self):
    3529        return self.connection is not None
    3630
    3731    def cursor(self):
     32        settings = self.settings
    3833        if not self._valid_connection():
    3934            if len(settings.DATABASE_HOST.strip()) == 0:
    4035                settings.DATABASE_HOST = 'localhost'
     
    7368needs_datetime_string_cast = False
    7469needs_upper_for_iops = True
    7570supports_constraints = True
     71supports_compound_statements = True
    7672supports_tablespaces = True
    7773uses_case_insensitive_names = True
    7874
  • django/db/backends/oracle/client.py

    === django/db/backends/oracle/client.py
    ==================================================================
     
    1 from django.conf import settings
    21import os
    32
    4 def runshell():
     3def runshell(settings):
    54    dsn = settings.DATABASE_USER
    65    if settings.DATABASE_PASSWORD:
    76        dsn += "/%s" % settings.DATABASE_PASSWORD
  • django/db/backends/postgresql_psycopg2/base.py

    === django/db/backends/postgresql_psycopg2/base.py
    ==================================================================
     
    2424postgres_version = None
    2525
    2626class DatabaseWrapper(local):
    27     def __init__(self, **kwargs):
     27    def __init__(self, settings):
     28        self.settings = settings
    2829        self.connection = None
    2930        self.queries = []
    30         self.options = kwargs
     31        self.options = settings.DATABASE_OPTIONS
    3132
    3233    def cursor(self):
    33         from django.conf import settings
     34        settings = self.settings
    3435        set_tz = False
    3536        if self.connection is None:
    3637            set_tz = True
     
    7980needs_datetime_string_cast = False
    8081needs_upper_for_iops = False
    8182supports_constraints = True
     83supports_compound_statements = True
    8284supports_tablespaces = False
    8385uses_case_insensitive_names = False
    8486
  • django/db/backends/ansi/__init__.py

    === django/db/backends/ansi/__init__.py
    ==================================================================
     
     1pass
  • django/db/backends/ansi/sql.py

    === django/db/backends/ansi/sql.py
    ==================================================================
     
     1"""ANSISQL schema manipulation functions and classes
     2"""
     3import os
     4import re
     5from django.db import models
     6from django.contrib.contenttypes import generic
     7
     8# For Python 2.3
     9if not hasattr(__builtins__, 'set'):
     10    from sets import Set as set
     11
     12# default dummy style
     13class dummy:
     14    def __getattr__(self, attr):
     15        return lambda x: x
     16default_style = dummy()
     17del dummy
     18
     19class BoundStatement(object):
     20    """Represents an SQL statement that is to be executed, at some point in
     21    the future, using a specific database connection.
     22    """
     23    def __init__(self, sql, connection):
     24        self.sql = sql
     25        self.connection = connection
     26
     27    def execute(self):
     28        cursor = self.connection.cursor()
     29        cursor.execute(self.sql)
     30
     31    def __repr__(self):
     32        return "BoundStatement(%r)" % self.sql
     33
     34    def __str__(self):
     35        return self.sql
     36
     37    def __eq__(self, other):
     38        return self.sql == other.sql and self.connection == other.connection
     39
     40class SchemaBuilder(object):
     41    """Basic ANSI SQL schema element builder. Instances of this class may be
     42    used to construct SQL expressions that create or drop schema elements such
     43    as tables, indexes and (for those backends that support them) foreign key
     44    or other constraints.
     45    """
     46    def __init__(self):
     47        # models that I have created
     48        self.models_already_seen = set()
     49        # model references, keyed by the referrent model
     50        self.references = {}
     51        # table cache; set to short-circuit table lookups
     52        self.tables = None
     53       
     54    def get_create_table(self, model, style=None, pending=None):
     55        """Construct and return the SQL expression(s) needed to create the
     56        table for the given model, and any constraints on that
     57        table. The return value is a 2-tuple. The first element of the tuple
     58        is a list of BoundStatements that may be executed immediately. The
     59        second is a dict of BoundStatements representing constraints that
     60        can't be executed immediately because (for instance) the referent
     61        table does not exist, keyed by the model class they reference.
     62        """
     63        if style is None:
     64            style = default_style
     65        if pending is None:
     66            pending = {}
     67        self.models_already_seen.add(model)
     68       
     69        opts = model._meta
     70        db = model._default_manager.db
     71        backend = db.backend
     72        quote_name = backend.quote_name
     73        data_types = db.get_creation_module().DATA_TYPES
     74        table_output = []
     75
     76        for f in opts.fields:
     77            if isinstance(f, (models.ForeignKey, models.OneToOneField)):
     78                rel_field = f.rel.get_related_field()
     79                data_type = self.get_rel_data_type(rel_field)
     80            else:
     81                rel_field = f
     82                data_type = f.get_internal_type()
     83            col_type = data_types[data_type]
     84            if col_type is not None:
     85                # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
     86                field_output = [style.SQL_FIELD(quote_name(f.column)),
     87                    style.SQL_COLTYPE(col_type % rel_field.__dict__)]
     88                field_output.append(style.SQL_KEYWORD(
     89                        '%sNULL' % (not f.null and 'NOT ' or '')))
     90                if f.unique:
     91                    field_output.append(style.SQL_KEYWORD('UNIQUE'))
     92                if f.primary_key:
     93                    field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
     94                if f.rel:
     95                    if f.rel.to in self.models_already_seen:
     96                        field_output.append(
     97                            style.SQL_KEYWORD('REFERENCES') + ' ' +
     98                            style.SQL_TABLE(
     99                                quote_name(f.rel.to._meta.db_table)) + ' (' +
     100                            style.SQL_FIELD(
     101                                quote_name(f.rel.to._meta.get_field(
     102                                        f.rel.field_name).column)) + ')'
     103                        )
     104                    else:
     105                        # We haven't yet created the table to which this field
     106                        # is related, so save it for later.
     107                        if backend.supports_constraints:
     108                            pending.setdefault(f.rel.to, []).append((model, f))
     109                table_output.append(' '.join(field_output))
     110        if opts.order_with_respect_to:
     111            table_output.append(style.SQL_FIELD(quote_name('_order')) + ' ' + \
     112                style.SQL_COLTYPE(data_types['IntegerField']) + ' ' + \
     113                style.SQL_KEYWORD('NULL'))
     114        for field_constraints in opts.unique_together:
     115            table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
     116                ", ".join([quote_name(style.SQL_FIELD(
     117                                opts.get_field(f).column))
     118                           for f in field_constraints]))
     119
     120        full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' +
     121                          style.SQL_TABLE(quote_name(opts.db_table)) + ' (']
     122        for i, line in enumerate(table_output): # Combine and add commas.
     123            full_statement.append('    %s%s' %
     124                                  (line, i < len(table_output)-1 and ',' or ''))
     125        full_statement.append(');')
     126        create = [BoundStatement('\n'.join(full_statement), db.connection)]
     127
     128        # Pull out any pending statements for me
     129        if pending:
     130            if model in pending:
     131                for rel_class, f in pending[model]:
     132                    create.append(self.get_ref_sql(model, rel_class, f,
     133                                                   style=style))
     134                # What was pending for me is now no longer pending
     135                pending.pop(model)
     136        return (create, pending)   
     137
     138    def get_create_indexes(self, model, style=None):
     139        """Construct and return SQL statements needed to create the indexes for
     140        a model. Returns a list of BoundStatements.
     141        """
     142        if style is None:
     143            style = default_style
     144        db = model._default_manager.db
     145        backend = db.backend
     146        connection = db.connection
     147        output = []
     148        for f in model._meta.fields:
     149            if f.db_index:
     150                unique = f.unique and 'UNIQUE ' or ''
     151                output.append(
     152                    BoundStatement(
     153                        ' '.join(
     154                            [style.SQL_KEYWORD('CREATE %sINDEX' % unique),
     155                             style.SQL_TABLE('%s_%s' %
     156                                             (model._meta.db_table, f.column)),
     157                             style.SQL_KEYWORD('ON'),
     158                             style.SQL_TABLE(
     159                                    backend.quote_name(model._meta.db_table)),
     160                             "(%s);" % style.SQL_FIELD(
     161                                    backend.quote_name(f.column))]),
     162                        connection)
     163                    )
     164        return output
     165
     166    def get_create_many_to_many(self, model, style=None):
     167        """Construct and return SQL statements needed to create the
     168        tables and relationships for all many-to-many relations
     169        defined in the model. Returns a list of bound statments. Note
     170        that these statements should only be executed after all models
     171        for an app have been created.
     172        """
     173        if style is None:
     174            style = default_style
     175        db = model._default_manager.db
     176        quote_name = db.backend.quote_name
     177        connection = db.connection
     178        data_types = db.get_creation_module().DATA_TYPES
     179        opts = model._meta
     180
     181        # statements to execute, keyed by the other model
     182        output = {}       
     183        for f in opts.many_to_many:
     184            if not isinstance(f.rel, generic.GenericRel):
     185                table_output = [
     186                    style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
     187                    style.SQL_TABLE(quote_name(f.m2m_db_table())) + ' (']
     188                table_output.append('    %s %s %s,' % \
     189                    (style.SQL_FIELD(quote_name('id')),
     190                    style.SQL_COLTYPE(data_types['AutoField']),
     191                    style.SQL_KEYWORD('NOT NULL PRIMARY KEY')))
     192                table_output.append('    %s %s %s %s (%s),' % \
     193                    (style.SQL_FIELD(quote_name(f.m2m_column_name())),
     194                    style.SQL_COLTYPE(data_types[self.get_rel_data_type(opts.pk)] % opts.pk.__dict__),
     195                    style.SQL_KEYWORD('NOT NULL REFERENCES'),
     196                    style.SQL_TABLE(quote_name(opts.db_table)),
     197                    style.SQL_FIELD(quote_name(opts.pk.column))))
     198                table_output.append('    %s %s %s %s (%s),' % \
     199                    (style.SQL_FIELD(quote_name(f.m2m_reverse_name())),
     200                    style.SQL_COLTYPE(data_types[self.get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__),
     201                    style.SQL_KEYWORD('NOT NULL REFERENCES'),
     202                    style.SQL_TABLE(quote_name(f.rel.to._meta.db_table)),
     203                    style.SQL_FIELD(quote_name(f.rel.to._meta.pk.column))))
     204                table_output.append('    %s (%s, %s)' % \
     205                    (style.SQL_KEYWORD('UNIQUE'),
     206                    style.SQL_FIELD(quote_name(f.m2m_column_name())),
     207                    style.SQL_FIELD(quote_name(f.m2m_reverse_name()))))
     208                table_output.append(');')
     209                output.setdefault(f.rel.to, []).append(
     210                    BoundStatement('\n'.join(table_output), connection))
     211        return output
     212
     213    def get_drop_table(self, model, cascade=False, style=None):
     214        """Construct and return the SQL statment(s) needed to drop a model's
     215        table. If cascade is true, then output additional statments to drop any
     216        many-to-many tables that this table created and any foreign keys that
     217        reference this table.
     218        """
     219        if style is None:
     220            style = default_style
     221        opts = model._meta
     222        db = model._default_manager.db
     223        db_table = opts.db_table
     224        backend = db.backend
     225        qn = backend.quote_name
     226        output = []
     227        output.append(BoundStatement(
     228                '%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
     229                            style.SQL_TABLE(qn(db_table))),
     230                db.connection))
     231
     232        if cascade:
     233            # deal with others that might have a foreign key TO me: alter
     234            # their tables to drop the constraint
     235            if backend.supports_constraints:
     236                references_to_delete = self.get_references()
     237                if model in references_to_delete:
     238                    for rel_class, f in references_to_delete[model]:
     239                        table = rel_class._meta.db_table
     240                        if not self.table_exists(db, table):
     241                            print "NO TABLE %s" % table
     242                            continue
     243                        col = f.column
     244                        r_table = opts.db_table
     245                        r_col = opts.get_field(f.rel.field_name).column
     246                        output.append(BoundStatement(
     247                            '%s %s %s %s;' %
     248                            (style.SQL_KEYWORD('ALTER TABLE'),
     249                             style.SQL_TABLE(qn(table)),
     250                             style.SQL_KEYWORD(
     251                                        backend.get_drop_foreignkey_sql()),
     252                             style.SQL_FIELD(qn("%s_refs_%s_%x" %
     253                                                (col, r_col,
     254                                                 abs(hash((table, r_table)))))
     255                                             )),                           
     256                            db.connection))
     257                    del references_to_delete[model]
     258            # many to many: drop any many-many tables that are my
     259            # responsiblity
     260            for f in opts.many_to_many:
     261                if not isinstance(f.rel, generic.GenericRel):
     262                    output.append(BoundStatement(
     263                            '%s %s;' %
     264                            (style.SQL_KEYWORD('DROP TABLE'),
     265                             style.SQL_TABLE(qn(f.m2m_db_table()))),
     266                            db.connection))
     267        return output
     268       
     269    def get_initialdata(self, model):
     270        opts = model._meta
     271        db = model._default_manager.db
     272        settings = db.connection.settings
     273        backend = db.backend
     274        app_dir = self.get_initialdata_path(model)
     275        output = []
     276
     277        # Some backends can't execute more than one SQL statement at a time.
     278        # We'll split the initial data into individual statements unless
     279        # backend.supports_compound_statements.
     280        statements = re.compile(r";[ \t]*$", re.M)
     281
     282        # Find custom SQL, if it's available.
     283        sql_files = [os.path.join(app_dir, "%s.%s.sql" %
     284                                  (opts.object_name.lower(),
     285                                   settings.DATABASE_ENGINE)),
     286                     os.path.join(app_dir, "%s.sql" %
     287                                  opts.object_name.lower())]
     288        for sql_file in sql_files:
     289            if os.path.exists(sql_file):
     290                fp = open(sql_file, 'U')
     291                if backend.supports_compound_statements:
     292                    output.append(BoundStatement(fp.read(), db.connection))
     293                else:                                 
     294                    for statement in statements.split(fp.read()):
     295                        # Remove any comments from the file
     296                        statement = re.sub(r"--.*[\n\Z]", "", statement)
     297                        if statement.strip():
     298                            output.append(BoundStatement(statement + ";",
     299                                                         db.connection))
     300                fp.close()
     301        return output
     302
     303    def get_initialdata_path(self, model):
     304        """Get the path from which to load sql initial data files for a model.
     305        """
     306        return os.path.normpath(os.path.join(os.path.dirname(
     307                    models.get_app(model._meta.app_label).__file__), 'sql'))
     308           
     309    def get_rel_data_type(self, f):
     310        return (f.get_internal_type() in ('AutoField', 'PositiveIntegerField',
     311                                          'PositiveSmallIntegerField')) \
     312                                          and 'IntegerField' \
     313                                          or f.get_internal_type()
     314
     315    def get_ref_sql(self, model, rel_class, f, style=None):
     316        """Get sql statement for a reference between model and rel_class on
     317        field f.
     318        """
     319        if style is None:
     320            style = default_style
     321       
     322        db = model._default_manager.db
     323        qn = db.backend.quote_name
     324        opts = model._meta
     325        rel_opts = rel_class._meta
     326        table = rel_opts.db_table
     327        r_col = f.column
     328        r_table = opts.db_table
     329        col = opts.get_field(f.rel.field_name).column
     330        # For MySQL, r_name must be unique in the first 64
     331        # characters. So we are careful with character usage here.
     332        r_name = '%s_refs_%s_%x' % (col, r_col,
     333                                    abs(hash((r_table, table))))
     334        sql = style.SQL_KEYWORD('ALTER TABLE') + \
     335              ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \
     336              (qn(table), qn(r_name),
     337               qn(r_col), qn(r_table), qn(col))
     338        return BoundStatement(sql, db.connection)
     339       
     340    def get_references(self):
     341        """Fill (if needed) and return the reference cache.
     342        """
     343        if self.references:
     344            return self.references
     345        for klass in models.get_models():
     346            for f in klass._meta.fields:
     347                if f.rel:
     348                    self.references.setdefault(f.rel.to,
     349                                               []).append((klass, f))
     350        return self.references
     351
     352    def get_table_list(self, db):
     353        """Get list of tables accessible via db.
     354        """
     355        if self.tables is not None:
     356            return self.tables
     357        cursor = db.connection.cursor()
     358        introspection = db.get_introspection_module()
     359        return introspection.get_table_list(cursor)       
     360   
     361    def table_exists(self, db, table):
     362        tables = self.get_table_list(db)
     363        return table in tables
  • django/db/backends/dummy/base.py

    === django/db/backends/dummy/base.py
    ==================================================================
     
    2222    pass
    2323
    2424class DatabaseWrapper:
     25   
    2526    cursor = complain
    2627    _commit = complain
    2728    _rollback = ignore
    2829
    29     def __init__(self, **kwargs):
    30         pass
     30    def __init__(self, settings):
     31        self.settings = settings
    3132
    3233    def close(self):
    3334        pass # close()
  • django/db/transaction.py

    === django/db/transaction.py
    ==================================================================
     
    1616    import thread
    1717except ImportError:
    1818    import dummy_thread as thread
    19 from django.db import connection
     19from django import db
    2020from django.conf import settings
    2121
    2222class TransactionManagementError(Exception):
     
    116116    Puts the transaction manager into a manual state: managed transactions have
    117117    to be committed explicitly by the user. If you switch off transaction
    118118    management and there is a pending commit/rollback, the data will be
    119     commited.
     119    commited. Note that managed state applies across all connections.
    120120    """
    121121    thread_ident = thread.get_ident()
    122122    top = state.get(thread_ident, None)
    123123    if top:
    124124        top[-1] = flag
    125125        if not flag and is_dirty():
    126             connection._commit()
     126            for cx in all_connections():
     127                cx._commit()
    127128            set_clean()
    128129    else:
    129130        raise TransactionManagementError("This code isn't under transaction management")
    130131
    131 def commit_unless_managed():
     132def commit_unless_managed(connections=None):
    132133    """
    133134    Commits changes if the system is not in managed transaction mode.
    134135    """
    135136    if not is_managed():
    136         connection._commit()
     137        if connections is None:
     138            connections = all_connections()
     139        else:
     140            connections = ensure_connections(connections)
     141        for cx in connections:
     142            cx._commit()
    137143    else:
    138144        set_dirty()
    139145
    140 def rollback_unless_managed():
     146def rollback_unless_managed(connections=None):
    141147    """
    142148    Rolls back changes if the system is not in managed transaction mode.
    143149    """
    144150    if not is_managed():
    145         connection._rollback()
     151        if connections is None:
     152            connections = all_connections()
     153        for cx in connections:
     154            cx._rollback()
    146155    else:
    147156        set_dirty()
    148157
    149 def commit():
     158def commit(connections=None):
    150159    """
    151160    Does the commit itself and resets the dirty flag.
    152161    """
    153     connection._commit()
     162    if connections is None:
     163        connections = all_connections()
     164    else:
     165        connections = ensure_connections(connections)
     166    for cx in connections:
     167        cx._commit()
    154168    set_clean()
    155169
    156 def rollback():
     170def rollback(connections=None):
    157171    """
    158172    This function does the rollback itself and resets the dirty flag.
    159173    """
    160     connection._rollback()
     174    if connections is None:
     175        connections = all_connections()
     176    else:
     177        connections = ensure_connections(connections)
     178    for cx in connections:
     179        cx._rollback()
    161180    set_clean()
    162181
    163182##############
     
    179198            leave_transaction_management()
    180199    return _autocommit
    181200
    182 def commit_on_success(func):
     201def commit_on_success(func, connections=None):
    183202    """
    184203    This decorator activates commit on response. This way, if the view function
    185204    runs successfully, a commit is made; if the viewfunc produces an exception,
     
    198217                raise
    199218            else:
    200219                if is_dirty():
    201                     commit()
     220                    commit(connections)
    202221            return res
    203222        finally:
    204223            leave_transaction_management()
     
    220239            leave_transaction_management()
    221240
    222241    return _commit_manually
     242
     243###########
     244# HELPERS #
     245###########
     246
     247def all_connections():
     248    return [db.connection] + [ c.connection
     249                               for c in db.connections.values() ]
     250
     251def ensure_connections(val):
     252    connections = []
     253    if isinstance(val, basestring):
     254        val = [val]
     255    try:
     256        iter(val)
     257    except:
     258        val = [val]
     259    for cx in val:
     260        if hasattr(cx, 'cursor'):
     261            connections.append(cx)
     262        elif hasattr(cx, 'connection'):
     263            connections.append(cx.connection)
     264        elif isinstance(cx, basestring):
     265            connections.append(db.connections[cx].connection)
     266    return connections
     267       
  • django/conf/global_settings.py

    === django/conf/global_settings.py
    ==================================================================
     
    112112DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
    113113DATABASE_OPTIONS = {}          # Set to empty dictionary for default.
    114114
     115# Optional named database connections in addition to the default.
     116OTHER_DATABASES = {}
     117
    115118# Host for sending e-mail.
    116119EMAIL_HOST = 'localhost'
    117120
     
    334337# If None, a name of 'test_' + DATABASE_NAME will be assumed
    335338TEST_DATABASE_NAME = None
    336339
     340# Tuple of other test databases to create. Names in this tuple
     341# are suffixes that will be appended to TEST_DATABASE_NAME
     342TEST_DATABASES = []
     343
     344# Models to assign to each test database. This must be a list of
     345# dicts, with each dict key being a name from TEST_DATABASES and value
     346# a list of models or app_labels that will use that database.
     347TEST_DATABASE_MODELS = []
     348
     349############### FROM TRUNK #############################
    337350# Strings used to set the character set and collation order for the test
    338351# database. These values are passed literally to the server, so they are
    339352# backend-dependent. If None, no special settings are sent (system defaults are
  • django/core/servers/basehttp.py

    === django/core/servers/basehttp.py
    ==================================================================
     
    309309        """
    310310        if not self.result_is_file() and not self.sendfile():
    311311            for data in self.result:
    312                 self.write(data)
     312                self.write(data, False)
    313313            self.finish_content()
    314314        self.close()
    315315
     
    377377        else:
    378378            self._write('Status: %s\r\n' % self.status)
    379379
    380     def write(self, data):
     380    def write(self, data, flush=True):
    381381        """'write()' callable as specified by PEP 333"""
    382382
    383383        assert type(data) is StringType,"write() argument must be string"
     
    394394
    395395        # XXX check Content-Length and truncate if too many bytes written?
    396396        self._write(data)
    397         self._flush()
     397        if flush:
     398            self._flush()
    398399
    399400    def sendfile(self):
    400401        """Platform-specific file transmission
     
    421422        if not self.headers_sent:
    422423            self.headers['Content-Length'] = "0"
    423424            self.send_headers()
    424         else:
    425             pass # XXX check if content-length was too short?
    426425
    427426    def close(self):
    428427        try:
  • django/core/management.py

    === django/core/management.py
    ==================================================================
     
    55from django.core.exceptions import ImproperlyConfigured
    66from optparse import OptionParser
    77from django.utils import termcolors
     8from django.db import model_connection_name
    89import os, re, shutil, sys, textwrap
    910
    10 try:
    11     set
    12 except NameError:
    13     from sets import Set as set   # Python 2.3 fallback
     11# For Python 2.3
     12if not hasattr(__builtins__, 'set'):
     13    from sets import Set as set
    1414
     15
    1516# For backwards compatibility: get_version() used to be in this module.
    1617get_version = django.get_version
    1718
     
    103104
    104105def get_sql_create(app):
    105106    "Returns a list of the CREATE TABLE SQL statements for the given app."
    106     from django.db import get_creation_module, models
     107    from django.db import get_creation_module, models, model_connection_name
    107108
    108     data_types = get_creation_module().DATA_TYPES
     109    # final output will be divided by comments into sections for each
     110    # named connection, if there are any named connections
     111    connection_output = {}
     112    pending = {}
     113    final_output = []
     114   
     115    app_models = models.get_models(app)#, creation_order=True)
     116    for model in app_models:
     117        opts = model._meta
     118        connection_name = model_connection_name(model)
     119        output = connection_output.setdefault(connection_name, [])
     120        db = model._default_manager.db
     121        creation = db.get_creation_module()
     122        data_types = creation.DATA_TYPES
     123        if not data_types:
     124            # This must be the "dummy" database backend, which means the user
     125            # hasn't set DATABASE_ENGINE.
    109126
    110     if not data_types:
    111         # This must be the "dummy" database backend, which means the user
    112         # hasn't set DATABASE_ENGINE.
    113         sys.stderr.write(style.ERROR("Error: Django doesn't know which syntax to use for your SQL statements,\n" +
    114             "because you haven't specified the DATABASE_ENGINE setting.\n" +
    115             "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n"))
    116         sys.exit(1)
     127            # FIXME diff error message for bad default v bad named
     128            sys.stderr.write(style.ERROR("Error: Django doesn't know which syntax to use for your SQL statements,\n" +
     129                                         "because you haven't specified the DATABASE_ENGINE setting.\n" +
     130                                         "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n"))
     131            sys.exit(1)
    117132
    118     # Get installed models, so we generate REFERENCES right.
    119     # We trim models from the current app so that the sqlreset command does not
    120     # generate invalid SQL (leaving models out of known_models is harmless, so
    121     # we can be conservative).
    122     app_models = models.get_models(app)
    123     final_output = []
    124     known_models = set([model for model in _get_installed_models(_get_table_list()) if model not in app_models])
    125     pending_references = {}
     133        # Get installed models, so we generate REFERENCES right
     134        # We trim models from the current app so that the sqlreset command does
     135        # not generate invalid SQL (leaving models out of known_models is
     136        # harmless, so we can be conservative).
     137        manager = model._default_manager
     138        try:
     139            tables = manager.get_table_list()
     140        except (KeyboardInterrupt, SystemExit):
     141            raise
     142        except:
     143            # Something else went wrong -- maybe the database isn't
     144            # running. But we can still generate sql, so use an empty
     145            # table list.
     146            tables = []
    126147
    127     for model in app_models:
    128         output, references = _get_sql_model_create(model, known_models)
    129         final_output.extend(output)
    130         for refto, refs in references.items():
    131             pending_references.setdefault(refto,[]).extend(refs)
    132         final_output.extend(_get_sql_for_pending_references(model, pending_references))
    133         # Keep track of the fact that we've created the table for this model.
    134         known_models.add(model)
     148        installed_models = [ m for m in
     149                             manager.get_installed_models(tables)
     150                             if m not in app_models ]
     151        models_output = set(installed_models)
     152        builder = creation.builder
     153        builder.models_already_seen.update(models_output)
     154        model_output, pending = builder.get_create_table(model, style, pending)
     155        output.extend(model_output)
    135156
    136     # Create the many-to-many join tables.
    137     for model in app_models:
    138         final_output.extend(_get_many_to_many_sql_for_model(model))
     157        # Create the many-to-many join tables.
     158        many_many = builder.get_create_many_to_many(model, style)
     159        for refmodel, statements in many_many.items():
     160            output.extend(statements)
    139161
     162    final_output = _collate(connection_output)
     163   
    140164    # Handle references to tables that are from other apps
    141165    # but don't exist physically
    142     not_installed_models = set(pending_references.keys())
     166    not_installed_models = set(pending.keys())
    143167    if not_installed_models:
    144168        alter_sql = []
    145169        for model in not_installed_models:
    146             alter_sql.extend(['-- ' + sql for sql in
    147                 _get_sql_for_pending_references(model, pending_references)])
     170            builder = model._default_manager.db.get_creation_module().builder
     171           
     172            for rel_class, f in pending[model]:
     173                sql = builder.get_ref_sql(model, rel_class, f, style)
     174                alter_sql.append('-- '+ str(sql))
    148175        if alter_sql:
    149             final_output.append('-- The following references should be added but depend on non-existent tables:')
     176            final_output.append('-- The following references should be added '
     177                                'but depend on non-existent tables:')
    150178            final_output.extend(alter_sql)
    151 
     179    # convert BoundStatements into strings
     180    final_output = map(str, final_output)
    152181    return final_output
    153182get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given app name(s)."
    154183get_sql_create.args = APP_ARGS
     
    314343
    315344def get_sql_delete(app):
    316345    "Returns a list of the DROP TABLE SQL statements for the given app."
     346    from django.db import model_connection_name
    317347    from django.db import backend, connection, models, get_introspection_module
    318348    from django.db.backends.util import truncate_name
    319349    introspection = get_introspection_module()
    320 
    321     # This should work even if a connection isn't available
    322     try:
    323         cursor = connection.cursor()
    324     except:
    325         cursor = None
    326 
    327     # Figure out which tables already exist
    328     if cursor:
    329         table_names = introspection.get_table_list(cursor)
    330     else:
    331         table_names = []
    332     if backend.uses_case_insensitive_names:
    333         table_name_converter = str.upper
    334     else:
    335         table_name_converter = lambda x: x
    336 
    337     output = []
    338 
    339     # Output DROP TABLE statements for standard application tables.
    340     to_delete = set()
    341 
    342     references_to_delete = {}
     350   
     351    connection_output = {}
     352    final_output = []
    343353    app_models = models.get_models(app)
    344354    for model in app_models:
    345         if cursor and table_name_converter(model._meta.db_table) in table_names:
    346             # The table exists, so it needs to be dropped
    347             opts = model._meta
    348             for f in opts.fields:
    349                 if f.rel and f.rel.to not in to_delete:
    350                     references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
    351 
    352             to_delete.add(model)
    353 
    354     for model in app_models:
    355         if cursor and table_name_converter(model._meta.db_table) in table_names:
    356             # Drop the table now
    357             output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
    358                 style.SQL_TABLE(backend.quote_name(model._meta.db_table))))
    359             if backend.supports_constraints and model in references_to_delete:
    360                 for rel_class, f in references_to_delete[model]:
    361                     table = rel_class._meta.db_table
    362                     col = f.column
    363                     r_table = model._meta.db_table
    364                     r_col = model._meta.get_field(f.rel.field_name).column
    365                     r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
    366                     output.append('%s %s %s %s;' % \
    367                         (style.SQL_KEYWORD('ALTER TABLE'),
    368                         style.SQL_TABLE(backend.quote_name(table)),
    369                         style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()),
    370                         style.SQL_FIELD(truncate_name(r_name, backend.get_max_name_length()))))
    371                 del references_to_delete[model]
    372             if model._meta.has_auto_field and hasattr(backend, 'get_drop_sequence'):
    373                 output.append(backend.get_drop_sequence(model._meta.db_table))
    374 
    375     # Output DROP TABLE statements for many-to-many tables.
    376     for model in app_models:
    377         opts = model._meta
    378         for f in opts.many_to_many:
    379             if cursor and table_name_converter(f.m2m_db_table()) in table_names:
    380                 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
    381                     style.SQL_TABLE(backend.quote_name(f.m2m_db_table()))))
    382                 if hasattr(backend, 'get_drop_sequence'):
    383                     output.append(backend.get_drop_sequence("%s_%s" % (model._meta.db_table, f.column)))
    384 
    385 
    386     app_label = app_models[0]._meta.app_label
    387 
    388     # Close database connection explicitly, in case this output is being piped
    389     # directly into a database client, to avoid locking issues.
    390     if cursor:
    391         cursor.close()
    392         connection.close()
    393 
    394     return output[::-1] # Reverse it, to deal with table dependencies.
     355        db = model._default_manager.db
     356        connection = db.connection
     357        try:
     358            cursor = connection.cursor()
     359        except:
     360            cursor = None
     361        #******** Start of conflict section ######
     362        ###** From multi-db
     363        builder = db.get_creation_module().builder
     364        connection_name = model_connection_name(model)
     365        output = connection_output.setdefault(connection_name, [])
     366        output.extend(map(str,
     367                          builder.get_drop_table(model,
     368                                                 cascade=True, style=style)))
     369        if cursor:
     370            # Close database connection explicitly, in case this
     371            # output is being piped directly into a database client,
     372            # to avoid locking issues.
     373            cursor.close()
     374            connection.close()
     375   
     376    final_output = _collate(connection_output, reverse=True)
     377    return final_output
    395378get_sql_delete.help_doc = "Prints the DROP TABLE SQL statements for the given app name(s)."
    396379get_sql_delete.args = APP_ARGS
    397380
     
    439422def get_custom_sql(app):
    440423    "Returns a list of the custom table modifying SQL statements for the given app."
    441424    from django.db.models import get_models
    442     output = []
     425    connection_output = {}
    443426
    444427    app_models = get_models(app)
    445428    app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
    446429
    447430    for model in app_models:
    448         output.extend(get_custom_sql_for_model(model))
     431        opts = model._meta
     432        connection_name = model_connection_name(model)
     433        output = connection_output.setdefault(connection_name, [])
     434        builder = model._default_manager.db.get_creation_module().builder
     435        output.extend(builder.get_initialdata(model))
    449436
    450     return output
     437    return _collate(connection_output)
    451438get_custom_sql.help_doc = "Prints the custom table modifying SQL statements for the given app name(s)."
    452439get_custom_sql.args = APP_ARGS
    453440
     
    458445get_sql_initial_data.args = ''
    459446
    460447def get_sql_sequence_reset(app):
    461     "Returns a list of the SQL statements to reset sequences for the given app."
    462     from django.db import backend, models
    463     return backend.get_sql_sequence_reset(style, models.get_models(app))
    464 get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting sequences for the given app name(s)."
     448    "Returns a list of the SQL statements to reset PostgreSQL sequences for the given app."
     449    from django.db import model_connection_name
     450    from django.db.models import get_models
     451    connection_output = {}
     452    for model in get_models(app):
     453        connection_name = model_connection_name(model)
     454        output = connection_output.setdefault(connection_name, [])
     455        builder = model._default_manager.db.get_creation_module().builder
     456        try:
     457            output.extend(builder.get_sequence_reset(model, style))
     458        except AttributeError:
     459            sys.stderr.write(
     460                "%s is configured to use database engine %s, which does "
     461                "not support sequence reset.\n" %
     462                (model.__name__,
     463                 model._default_manager.db.connection.settings.DATABASE_ENGINE))
     464   
     465    return _collate(connection_output)
     466get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting PostgreSQL sequences for the given app name(s)."
    465467get_sql_sequence_reset.args = APP_ARGS
    466468
    467469def get_sql_indexes(app):
    468470    "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
    469     from django.db import models
    470     output = []
    471     for model in models.get_models(app):
    472         output.extend(get_sql_indexes_for_model(model))
    473     return output
     471    from django.db import model_connection_name
     472    from django.db.models import get_models
     473    connection_output = {}
     474    for model in get_models(app):
     475        opts = model._meta
     476        connection_name = model_connection_name(model)
     477        output = connection_output.setdefault(connection_name, [])
     478        output.extend(map(str, get_sql_indexes_for_model(model)))
     479    return _collate(connection_output)
     480
    474481get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
    475482get_sql_indexes.args = APP_ARGS
    476483
     
    503510get_sql_all.help_doc = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)."
    504511get_sql_all.args = APP_ARGS
    505512
     513def _collate(connection_output, reverse=False):
     514    from django.db import _default
     515    final_output = []
     516    if len(connection_output.keys()) == 1:
     517        # all for the default connection
     518        for statements in connection_output.values():
     519            final_output.extend(statements)
     520            if reverse:
     521                final_output.reverse()
     522    else:
     523        for connection_name, statements in connection_output.items():
     524            if not statements:
     525                continue
     526            final_output.append(' -- The following statements are for connection: %s' % connection_name)
     527            if reverse:
     528                statements.reverse()
     529            final_output.extend(statements)
     530            final_output.append(' -- END statements for %s\n' %
     531                                connection_name)
     532    return map(str, final_output)
     533
    506534def _emit_post_sync_signal(created_models, verbosity, interactive):
    507535    from django.db import models
    508536    from django.dispatch import dispatcher
     
    687715    print '\n'.join(output)
    688716diffsettings.args = ""
    689717
     718def install(app):
     719    "Executes the equivalent of 'get_sql_all' in the current database."
     720    # Wrap _install to hide the return value so ./manage.py install
     721    # doesn't complain about unprintable output.   
     722    _install(app)
     723
     724def _install(app, commit=True, initial_data=True, pending_allowed=False,
     725             pending=None, verbosity=1, signal=True, interactive=True):
     726    from django.db import connection, models, transaction
     727    import sys
     728   
     729    app_name = app.__name__.split('.')[-2]
     730
     731    disable_termcolors()
     732
     733    # First, try validating the models.
     734    _check_for_validation_errors(app)
     735
     736    created_models = []
     737    try:
     738        if pending is None:
     739            pending = {}
     740        for model in models.get_models(app, creation_order=True):
     741            if verbosity >= 2:
     742                print "Processing %s.%s model" % (app_name,
     743                                                  model._meta.object_name)
     744            manager = model._default_manager
     745            tables = manager.get_table_list()
     746            models_installed = manager.get_installed_models(tables)
     747            # Don't re-install already-installed models
     748            if not model in models_installed:
     749                pending = manager.install(initial_data=initial_data,
     750                                          pending=pending)
     751                created_models.append(model)
     752               
     753        if pending:           
     754            models_installed = manager.get_installed_models(tables)
     755
     756            for model in pending.keys():
     757                manager = model._default_manager
     758                if model in models_installed:
     759                    for rel_class, f in pending[model]:
     760                        manager.get_pending(rel_class, f).execute()
     761                    pending.pop(model)
     762                elif not pending_allowed:
     763                    raise Exception("%s is not installed, but it has pending "
     764                                    "references" % model)
     765    except Exception, e:
     766        import traceback
     767        print traceback.format_exception(*sys.exc_info())
     768        sys.stderr.write(style.ERROR("""Error: %s couldn't be installed. Possible reasons:
     769  * The database isn't running or isn't configured correctly.
     770  * At least one of the database tables already exists.
     771  * The SQL was invalid.
     772Hint: Look at the output of 'django-admin.py sqlall %s'. That's the SQL this command wasn't able to run.
     773The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
     774        transaction.rollback_unless_managed()
     775        sys.exit(1)
     776    if commit:
     777        transaction.commit_unless_managed()
     778
     779    if signal:
     780        _post_syncdb(app, created_models=created_models,
     781                     verbosity=verbosity, interactive=interactive)
     782       
     783    return created_models, pending
     784install.help_doc = "Executes ``sqlall`` for the given app(s) in the current database."
     785install.args = APP_ARGS
     786
     787def _post_syncdb(app, created_models, verbosity=1, interactive=True):
     788    """Send the post_syncdb signal for an application."""
     789    from django.dispatch import dispatcher
     790    from django.db.models import signals
     791   
     792    if verbosity >= 2:
     793        print "Sending post-syncdb signal for application", app.__name__.split('.')[-2]
     794    dispatcher.send(signal=signals.post_syncdb, sender=app,
     795                    app=app, created_models=created_models,
     796                    verbosity=verbosity, interactive=interactive)
     797
    690798def reset(app, interactive=True):
    691799    "Executes the equivalent of 'get_sql_reset' in the current database."
    692800    from django.db import connection, transaction
     
    9831091    Returns number of errors.
    9841092    """
    9851093    from django.conf import settings
    986     from django.db import models, connection
     1094    from django.db import connections, models, connection, model_connection_name
    9871095    from django.db.models.loading import get_app_errors
    9881096    from django.db.models.fields.related import RelatedObject
    9891097
     
    9941102
    9951103    for cls in models.get_models(app):
    9961104        opts = cls._meta
    997 
     1105        connection_name = model_connection_name(cls)
     1106        connection = connections[connection_name]
     1107       
    9981108        # Do field-specific validation.
    9991109        for f in opts.fields:
    10001110            if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
     
    10271137
    10281138            # Check that maxlength <= 255 if using older MySQL versions.
    10291139            if settings.DATABASE_ENGINE == 'mysql':
    1030                 db_version = connection.get_server_version()
     1140                db_version = connection.connection.get_server_version()
    10311141                if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.maxlength > 255:
    10321142                    e.add(opts, '"%s": %s cannot have a "maxlength" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
    10331143
     
    10381148                if f.rel.to not in models.get_models():
    10391149                    e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
    10401150
     1151                #TODO: Fix this to allow relations that span databases by splitting querys up
     1152                rel_connection = model_connection_name(f.rel.to)
     1153                if rel_connection != connection_name:
     1154                    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))
     1155
    10411156                rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
    10421157                rel_query_name = f.related_query_name()
    10431158                for r in rel_opts.fields:
     
    15461661    'createcachetable',
    15471662    'dbshell',
    15481663    'diffsettings',
     1664    'install',
    15491665    'reset',
    15501666    'sqlindexes',
    15511667    'syncdb',
  • django/views/generic/simple.py

    Property changes on: django/core/management.py
    ___________________________________________________________________
    Name: svn:eol-style
     -native
    
    === django/views/generic/simple.py
    ==================================================================
     
    1515            dictionary[key] = value
    1616    c = RequestContext(request, dictionary)
    1717    t = loader.get_template(template)
    18     return HttpResponse(t.render(c), mimetype=mimetype)
     18    return HttpResponse(t.iter_render(c), mimetype=mimetype)
    1919
    2020def redirect_to(request, url, **kwargs):
    2121    """
  • django/views/generic/date_based.py

    === django/views/generic/date_based.py
    ==================================================================
     
    4444            c[key] = value()
    4545        else:
    4646            c[key] = value
    47     return HttpResponse(t.render(c), mimetype=mimetype)
     47    return HttpResponse(t.iter_render(c), mimetype=mimetype)
    4848
    4949def archive_year(request, year, queryset, date_field, template_name=None,
    5050        template_loader=loader, extra_context=None, allow_empty=False,
     
    9292            c[key] = value()
    9393        else:
    9494            c[key] = value
    95     return HttpResponse(t.render(c), mimetype=mimetype)
     95    return HttpResponse(t.iter_render(c), mimetype=mimetype)
    9696
    9797def archive_month(request, year, month, queryset, date_field,
    9898        month_format='%b', template_name=None, template_loader=loader,
     
    158158            c[key] = value()
    159159        else:
    160160            c[key] = value
    161     return HttpResponse(t.render(c), mimetype=mimetype)
     161    return HttpResponse(t.iter_render(c), mimetype=mimetype)
    162162
    163163def archive_week(request, year, week, queryset, date_field,
    164164        template_name=None, template_loader=loader,
     
    206206            c[key] = value()
    207207        else:
    208208            c[key] = value
    209     return HttpResponse(t.render(c), mimetype=mimetype)
     209    return HttpResponse(t.iter_render(c), mimetype=mimetype)
    210210
    211211def archive_day(request, year, month, day, queryset, date_field,
    212212        month_format='%b', day_format='%d', template_name=None,
     
    270270            c[key] = value()
    271271        else:
    272272            c[key] = value
    273     return HttpResponse(t.render(c), mimetype=mimetype)
     273    return HttpResponse(t.iter_render(c), mimetype=mimetype)
    274274
    275275def archive_today(request, **kwargs):
    276276    """
     
    339339            c[key] = value()
    340340        else:
    341341            c[key] = value
    342     response = HttpResponse(t.render(c), mimetype=mimetype)
     342    response = HttpResponse(t.iter_render(c), mimetype=mimetype)
    343343    populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
    344344    return response
  • django/views/generic/list_detail.py

    === django/views/generic/list_detail.py
    ==================================================================
     
    8484        model = queryset.model
    8585        template_name = "%s/%s_list.html" % (model._meta.app_label, model._meta.object_name.lower())
    8686    t = template_loader.get_template(template_name)
    87     return HttpResponse(t.render(c), mimetype=mimetype)
     87    return HttpResponse(t.iter_render(c), mimetype=mimetype)
    8888
    8989def object_detail(request, queryset, object_id=None, slug=None,
    9090        slug_field=None, template_name=None, template_name_field=None,
     
    126126            c[key] = value()
    127127        else:
    128128            c[key] = value
    129     response = HttpResponse(t.render(c), mimetype=mimetype)
     129    response = HttpResponse(t.iter_render(c), mimetype=mimetype)
    130130    populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
    131131    return response
  • django/views/generic/create_update.py

    === django/views/generic/create_update.py
    ==================================================================
     
    6868            c[key] = value()
    6969        else:
    7070            c[key] = value
    71     return HttpResponse(t.render(c))
     71    return HttpResponse(t.iter_render(c))
    7272
    7373def update_object(request, model, object_id=None, slug=None,
    7474        slug_field=None, template_name=None, template_loader=loader,
     
    141141            c[key] = value()
    142142        else:
    143143            c[key] = value
    144     response = HttpResponse(t.render(c))
     144    response = HttpResponse(t.iter_render(c))
    145145    populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname))
    146146    return response
    147147
     
    195195                c[key] = value()
    196196            else:
    197197                c[key] = value
    198         response = HttpResponse(t.render(c))
     198        response = HttpResponse(t.iter_render(c))
    199199        populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname))
    200200        return response
  • django/views/debug.py

    === django/views/debug.py
    ==================================================================
     
    137137        'template_does_not_exist': template_does_not_exist,
    138138        'loader_debug_info': loader_debug_info,
    139139    })
    140     return HttpResponseServerError(t.render(c), mimetype='text/html')
     140    return HttpResponseServerError(t.iter_render(c), mimetype='text/html')
    141141
    142142def technical_404_response(request, exception):
    143143    "Create a technical 404 error response. The exception should be the Http404."
     
    160160        'request_protocol': request.is_secure() and "https" or "http",
    161161        'settings': get_safe_settings(),
    162162    })
    163     return HttpResponseNotFound(t.render(c), mimetype='text/html')
     163    return HttpResponseNotFound(t.iter_render(c), mimetype='text/html')
    164164
    165165def empty_urlconf(request):
    166166    "Create an empty URLconf 404 error response."
     
    168168    c = Context({
    169169        'project_name': settings.SETTINGS_MODULE.split('.')[0]
    170170    })
    171     return HttpResponseNotFound(t.render(c), mimetype='text/html')
     171    return HttpResponseNotFound(t.iter_render(c), mimetype='text/html')
    172172
    173173def _get_lines_from_file(filename, lineno, context_lines, loader=None, module_name=None):
    174174    """
  • django/views/defaults.py

    === django/views/defaults.py
    ==================================================================
     
    7676            The path of the requested URL (e.g., '/app/pages/bad_page/')
    7777    """
    7878    t = loader.get_template(template_name) # You need to create a 404.html template.
    79     return http.HttpResponseNotFound(t.render(RequestContext(request, {'request_path': request.path})))
     79    return http.HttpResponseNotFound(t.iter_render(RequestContext(request, {'request_path': request.path})))
    8080
    8181def server_error(request, template_name='500.html'):
    8282    """
     
    8686    Context: None
    8787    """
    8888    t = loader.get_template(template_name) # You need to create a 500.html template.
    89     return http.HttpResponseServerError(t.render(Context({})))
     89    return http.HttpResponseServerError(t.iter_render(Context({})))
  • django/views/static.py

    === django/views/static.py
    ==================================================================
     
    9292        'directory' : path + '/',
    9393        'file_list' : files,
    9494    })
    95     return HttpResponse(t.render(c))
     95    return HttpResponse(t.iter_render(c))
    9696
    9797def was_modified_since(header=None, mtime=0, size=0):
    9898    """
  • django/shortcuts/__init__.py

    === django/shortcuts/__init__.py
    ==================================================================
     
    77from django.db.models.manager import Manager
    88
    99def render_to_response(*args, **kwargs):
    10     return HttpResponse(loader.render_to_string(*args, **kwargs))
     10    return HttpResponse(loader.render_to_iter(*args, **kwargs))
    1111load_and_render = render_to_response # For backwards compatibility.
    1212
    1313def get_object_or_404(klass, *args, **kwargs):
  • django/contrib/comments/templatetags/comments.py

    === django/contrib/comments/templatetags/comments.py
    ==================================================================
     
    2424        self.photo_options, self.rating_options = photo_options, rating_options
    2525        self.is_public = is_public
    2626
    27     def render(self, context):
     27    def iter_render(self, context):
    2828        from django.conf import settings
    2929        from django.utils.text import normalize_newlines
    3030        import base64
     
    3333            try:
    3434                self.obj_id = template.resolve_variable(self.obj_id_lookup_var, context)
    3535            except template.VariableDoesNotExist:
    36                 return ''
     36                return
    3737            # Validate that this object ID is valid for this content-type.
    3838            # We only have to do this validation if obj_id_lookup_var is provided,
    3939            # because do_comment_form() validates hard-coded object IDs.
     
    6767            context['hash'] = Comment.objects.get_security_hash(context['options'], context['photo_options'], context['rating_options'], context['target'])
    6868            context['logout_url'] = settings.LOGOUT_URL
    6969            default_form = loader.get_template(COMMENT_FORM)
    70         output = default_form.render(context)
     70        for chunk in default_form.iter_render(context):
     71            yield chunk
    7172        context.pop()
    72         return output
    7373
    7474class CommentCountNode(template.Node):
    7575    def __init__(self, package, module, context_var_name, obj_id, var_name, free):
     
    7777        self.context_var_name, self.obj_id = context_var_name, obj_id
    7878        self.var_name, self.free = var_name, free
    7979
    80     def render(self, context):
     80    def iter_render(self, context):
    8181        from django.conf import settings
    8282        manager = self.free and FreeComment.objects or Comment.objects
    8383        if self.context_var_name is not None:
     
    8686            content_type__app_label__exact=self.package,
    8787            content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count()
    8888        context[self.var_name] = comment_count
    89         return ''
     89        return ()
    9090
    9191class CommentListNode(template.Node):
    9292    def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None):
     
    9696        self.ordering = ordering
    9797        self.extra_kwargs = extra_kwargs or {}
    9898
    99     def render(self, context):
     99    def iter_render(self, context):
    100100        from django.conf import settings
    101101        get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma
    102102        if self.context_var_name is not None:
    103103            try:
    104104                self.obj_id = template.resolve_variable(self.context_var_name, context)
    105105            except template.VariableDoesNotExist:
    106                 return ''
     106                return ()
    107107        kwargs = {
    108108            'object_id__exact': self.obj_id,
    109109            'content_type__app_label__exact': self.package,
     
    127127                comment_list = [c for c in comment_list if not c.is_hidden or (user_id == c.user_id)]
    128128
    129129        context[self.var_name] = comment_list
    130         return ''
     130        return ()
    131131
    132132class DoCommentForm:
    133133    """
  • django/contrib/admin/templatetags/admin_modify.py

    === django/contrib/admin/templatetags/admin_modify.py
    ==================================================================
     
    9494            return cls.nodelists[klass]
    9595    get_nodelist = classmethod(get_nodelist)
    9696
    97     def render(self, context):
     97    def iter_render(self, context):
    9898        bound_field = template.resolve_variable(self.bound_field_var, context)
    9999
    100100        context.push()
    101101        context['bound_field'] = bound_field
    102102
    103         output = self.get_nodelist(bound_field.field.__class__).render(context)
     103        for chunk in self.get_nodelist(bound_field.field.__class__).iter_render(context):
     104            yield chunk
    104105        context.pop()
    105         return output
    106106
    107107class FieldWrapper(object):
    108108    def __init__(self, field ):
     
    157157    def __init__(self, rel_var):
    158158        self.rel_var = rel_var
    159159
    160     def render(self, context):
     160    def iter_render(self, context):
    161161        relation = template.resolve_variable(self.rel_var, context)
    162162        context.push()
    163163        if relation.field.rel.edit_inline == models.TABULAR:
     
    169169        original = context.get('original', None)
    170170        bound_related_object = relation.bind(context['form'], original, bound_related_object_class)
    171171        context['bound_related_object'] = bound_related_object
    172         t = loader.get_template(bound_related_object.template_name())
    173         output = t.render(context)
     172        for chunk in loader.get_template(bound_related_object.template_name()).iter_render(context):
     173            yield chunk
    174174        context.pop()
    175         return output
    176175
    177176def output_all(form_fields):
    178177    return ''.join([str(f) for f in form_fields])
  • django/contrib/admin/templatetags/log.py

    === django/contrib/admin/templatetags/log.py
    ==================================================================
     
    1010    def __repr__(self):
    1111        return "<GetAdminLog Node>"
    1212
    13     def render(self, context):
     13    def iter_render(self, context):
    1414        if self.user is None:
    1515            context[self.varname] = LogEntry.objects.all().select_related()[:self.limit]
    1616        else:
    1717            if not self.user.isdigit():
    1818                self.user = context[self.user].id
    1919            context[self.varname] = LogEntry.objects.filter(user__id__exact=self.user).select_related()[:self.limit]
    20         return ''
     20        return ()
    2121
    2222class DoGetAdminLog:
    2323    """
  • django/contrib/admin/templatetags/adminapplist.py

    === django/contrib/admin/templatetags/adminapplist.py
    ==================================================================
     
    77    def __init__(self, varname):
    88        self.varname = varname
    99
    10     def render(self, context):
     10    def iter_render(self, context):
    1111        from django.db import models
    1212        from django.utils.text import capfirst
    1313        app_list = []
     
    5454                        'models': model_list,
    5555                    })
    5656        context[self.varname] = app_list
    57         return ''
     57        return ()
    5858
    5959def get_admin_app_list(parser, token):
    6060    """
  • django/template/__init__.py

    === django/template/__init__.py
    ==================================================================
     
    5555'\n<html>\n\n</html>\n'
    5656"""
    5757import re
     58import types
    5859from inspect import getargspec
    5960from django.conf import settings
    6061from django.template.context import Context, RequestContext, ContextPopException
     
    167168            for subnode in node:
    168169                yield subnode
    169170
    170     def render(self, context):
     171    def iter_render(self, context):
    171172        "Display stage -- can be called many times"
    172         return self.nodelist.render(context)
     173        return self.nodelist.iter_render(context)
    173174
     175    def render(self, context):
     176        return ''.join(self.iter_render(context))
     177
    174178def compile_string(template_string, origin):
    175179    "Compiles template_string into NodeList ready for rendering"
    176180    lexer = lexer_factory(template_string, origin)
     
    695699            del bits[0]
    696700    return current
    697701
     702class NodeBase(type):
     703    def __new__(cls, name, bases, attrs):
     704        """
     705        Ensures that either a 'render' or 'render_iter' method is defined on
     706        any Node sub-class. This avoids potential infinite loops at runtime.
     707        """
     708        if not (isinstance(attrs.get('render'), types.FunctionType) or
     709                isinstance(attrs.get('iter_render'), types.FunctionType)):
     710            raise TypeError('Unable to create Node subclass without either "render" or "iter_render" method.')
     711        return type.__new__(cls, name, bases, attrs)
     712
    698713class Node(object):
     714    __metaclass__ = NodeBase
     715
     716    def iter_render(self, context):
     717        return (self.render(context),)
     718
    699719    def render(self, context):
    700720        "Return the node rendered as a string"
    701         pass
     721        return ''.join(self.iter_render(context))
    702722
    703723    def __iter__(self):
    704724        yield self
     
    714734
    715735class NodeList(list):
    716736    def render(self, context):
    717         bits = []
     737        return ''.join(self.iter_render(context))
     738
     739    def iter_render(self, context):
    718740        for node in self:
    719             if isinstance(node, Node):
    720                 bits.append(self.render_node(node, context))
    721             else:
    722                 bits.append(node)
    723         return ''.join(bits)
     741            for chunk in node.iter_render(context):
     742                yield chunk
    724743
    725744    def get_nodes_by_type(self, nodetype):
    726745        "Return a list of all nodes of the given type"
     
    729748            nodes.extend(node.get_nodes_by_type(nodetype))
    730749        return nodes
    731750
    732     def render_node(self, node, context):
    733         return(node.render(context))
    734 
    735751class DebugNodeList(NodeList):
    736     def render_node(self, node, context):
    737         try:
    738             result = node.render(context)
    739         except TemplateSyntaxError, e:
    740             if not hasattr(e, 'source'):
    741                 e.source = node.source
    742             raise
    743         except Exception, e:
    744             from sys import exc_info
    745             wrapped = TemplateSyntaxError('Caught an exception while rendering: %s' % e)
    746             wrapped.source = node.source
    747             wrapped.exc_info = exc_info()
    748             raise wrapped
    749         return result
     752    def iter_render(self, context):
     753        for node in self:
     754            if not isinstance(node, Node):
     755                yield node
     756                continue
     757            try:
     758                for chunk in node.iter_render(context):
     759                    yield chunk
     760            except TemplateSyntaxError, e:
     761                if not hasattr(e, 'source'):
     762                    e.source = node.source
     763                raise
     764            except Exception, e:
     765                from sys import exc_info
     766                wrapped = TemplateSyntaxError('Caught an exception while rendering: %s' % e)
     767                wrapped.source = node.source
     768                wrapped.exc_info = exc_info()
     769                raise wrapped
    750770
    751771class TextNode(Node):
    752772    def __init__(self, s):
     
    755775    def __repr__(self):
    756776        return "<Text Node: '%s'>" % self.s[:25]
    757777
     778    def iter_render(self, context):
     779        return (self.s,)
     780
    758781    def render(self, context):
    759782        return self.s
    760783
     
    778801        else:
    779802            return output
    780803
     804    def iter_render(self, context):
     805        return (self.render(context),)
     806
    781807    def render(self, context):
    782808        output = self.filter_expression.resolve(context)
    783809        return self.encode_output(output)
     
    866892            def __init__(self, vars_to_resolve):
    867893                self.vars_to_resolve = vars_to_resolve
    868894
     895            #def iter_render(self, context):
     896            #    return (self.render(context),)
     897
    869898            def render(self, context):
    870899                resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
    871900                return func(*resolved_vars)
     
    888917                def __init__(self, vars_to_resolve):
    889918                    self.vars_to_resolve = vars_to_resolve
    890919
    891                 def render(self, context):
     920                def iter_render(self, context):
    892921                    resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
    893922                    if takes_context:
    894923                        args = [context] + resolved_vars
     
    904933                        else:
    905934                            t = get_template(file_name)
    906935                        self.nodelist = t.nodelist
    907                     return self.nodelist.render(context_class(dict))
     936                    return self.nodelist.iter_render(context_class(dict))
    908937
    909938            compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, InclusionNode)
    910939            compile_func.__doc__ = func.__doc__
  • django/template/defaulttags.py

    === django/template/defaulttags.py
    ==================================================================
     
    1616register = Library()
    1717
    1818class CommentNode(Node):
    19     def render(self, context):
    20         return ''
     19    def iter_render(self, context):
     20        return ()
    2121
    2222class CycleNode(Node):
    2323    def __init__(self, cyclevars, variable_name=None):
     
    2626        self.counter = -1
    2727        self.variable_name = variable_name
    2828
     29    def iter_render(self, context):
     30        return (self.render(context),)
     31
    2932    def render(self, context):
    3033        self.counter += 1
    3134        value = self.cyclevars[self.counter % self.cyclevars_len]
     
    3437        return value
    3538
    3639class DebugNode(Node):
    37     def render(self, context):
     40    def iter_render(self, context):
    3841        from pprint import pformat
    39         output = [pformat(val) for val in context]
    40         output.append('\n\n')
    41         output.append(pformat(sys.modules))
    42         return ''.join(output)
     42        for val in context:
     43            yield pformat(val)
     44        yield "\n\n"
     45        yield pformat(sys.modules)
    4346
    4447class FilterNode(Node):
    4548    def __init__(self, filter_expr, nodelist):
    4649        self.filter_expr, self.nodelist = filter_expr, nodelist
    4750
    48     def render(self, context):
     51    def iter_render(self, context):
    4952        output = self.nodelist.render(context)
    5053        # apply filters
    5154        context.update({'var': output})
    5255        filtered = self.filter_expr.resolve(context)
    5356        context.pop()
    54         return filtered
     57        return (filtered,)
    5558
    5659class FirstOfNode(Node):
    5760    def __init__(self, vars):
    5861        self.vars = vars
    5962
     63    def iter_render(self, context):
     64        return (self.render(context),)
     65
    6066    def render(self, context):
    6167        for var in self.vars:
    6268            try:
     
    9298        nodes.extend(self.nodelist_loop.get_nodes_by_type(nodetype))
    9399        return nodes
    94100
    95     def render(self, context):
    96         nodelist = NodeList()
     101    def iter_render(self, context):
    97102        if 'forloop' in context:
    98103            parentloop = context['forloop']
    99104        else:
     
    101106        context.push()
    102107        try:
    103108            values = self.sequence.resolve(context, True)
     109            if values is None:
     110                values = ()
     111            elif not hasattr(values, '__len__'):
     112                values = list(values)
    104113        except VariableDoesNotExist:
    105             values = []
    106         if values is None:
    107             values = []
    108         if not hasattr(values, '__len__'):
    109             values = list(values)
     114            values = ()
    110115        len_values = len(values)
    111116        if self.reversed:
    112117            values = reversed(values)
     
    125130                'parentloop': parentloop,
    126131            }
    127132            if unpack:
    128                 # If there are multiple loop variables, unpack the item into them.
     133                # If there are multiple loop variables, unpack the item into
     134                # them.
    129135                context.update(dict(zip(self.loopvars, item)))
    130136            else:
    131137                context[self.loopvars[0]] = item
     138
     139            # We inline this to avoid the overhead since ForNode is pretty
     140            # common.
    132141            for node in self.nodelist_loop:
    133                 nodelist.append(node.render(context))
     142                for chunk in node.iter_render(context):
     143                    yield chunk
    134144            if unpack:
    135145                # The loop variables were pushed on to the context so pop them
    136146                # off again. This is necessary because the tag lets the length
     
    139149                # context.
    140150                context.pop()
    141151        context.pop()
    142         return nodelist.render(context)
    143152
    144153class IfChangedNode(Node):
    145154    def __init__(self, nodelist, *varlist):
     
    147156        self._last_seen = None
    148157        self._varlist = varlist
    149158
    150     def render(self, context):
     159    def iter_render(self, context):
    151160        if 'forloop' in context and context['forloop']['first']:
    152161            self._last_seen = None
    153162        try:
     
    165174            self._last_seen = compare_to
    166175            context.push()
    167176            context['ifchanged'] = {'firstloop': firstloop}
    168             content = self.nodelist.render(context)
     177            for chunk in self.nodelist.iter_render(context):
     178                yield chunk
    169179            context.pop()
    170             return content
    171         else:
    172             return ''
    173180
    174181class IfEqualNode(Node):
    175182    def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
     
    180187    def __repr__(self):
    181188        return "<IfEqualNode>"
    182189
    183     def render(self, context):
     190    def iter_render(self, context):
    184191        try:
    185192            val1 = resolve_variable(self.var1, context)
    186193        except VariableDoesNotExist:
     
    190197        except VariableDoesNotExist:
    191198            val2 = None
    192199        if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
    193             return self.nodelist_true.render(context)
    194         return self.nodelist_false.render(context)
     200            return self.nodelist_true.iter_render(context)
     201        return self.nodelist_false.iter_render(context)
    195202
    196203class IfNode(Node):
    197204    def __init__(self, bool_exprs, nodelist_true, nodelist_false, link_type):
     
    216223        nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
    217224        return nodes
    218225
    219     def render(self, context):
     226    def iter_render(self, context):
    220227        if self.link_type == IfNode.LinkTypes.or_:
    221228            for ifnot, bool_expr in self.bool_exprs:
    222229                try:
     
    224231                except VariableDoesNotExist:
    225232                    value = None
    226233                if (value and not ifnot) or (ifnot and not value):
    227                     return self.nodelist_true.render(context)
    228             return self.nodelist_false.render(context)
     234                    return self.nodelist_true.iter_render(context)
     235            return self.nodelist_false.iter_render(context)
    229236        else:
    230237            for ifnot, bool_expr in self.bool_exprs:
    231238                try:
     
    233240                except VariableDoesNotExist:
    234241                    value = None
    235242                if not ((value and not ifnot) or (ifnot and not value)):
    236                     return self.nodelist_false.render(context)
    237             return self.nodelist_true.render(context)
     243                    return self.nodelist_false.iter_render(context)
     244            return self.nodelist_true.iter_render(context)
    238245
    239246    class LinkTypes:
    240247        and_ = 0,
     
    245252        self.target, self.expression = target, expression
    246253        self.var_name = var_name
    247254
    248     def render(self, context):
     255    def iter_render(self, context):
    249256        obj_list = self.target.resolve(context, True)
    250257        if obj_list == None: # target_var wasn't found in context; fail silently
    251258            context[self.var_name] = []
    252             return ''
     259            return ()
    253260        # List of dictionaries in the format
    254261        # {'grouper': 'key', 'list': [list of contents]}.
    255262        context[self.var_name] = [{'grouper':key, 'list':list(val)} for key, val in
    256263            groupby(obj_list, lambda v, f=self.expression.resolve: f(v, True))]
    257         return ''
     264        return ()
    258265
    259266def include_is_allowed(filepath):
    260267    for root in settings.ALLOWED_INCLUDE_ROOTS:
     
    266273    def __init__(self, filepath, parsed):
    267274        self.filepath, self.parsed = filepath, parsed
    268275
    269     def render(self, context):
     276    def iter_render(self, context):
    270277        if not include_is_allowed(self.filepath):
    271278            if settings.DEBUG:
    272                 return "[Didn't have permission to include file]"
     279                return ("[Didn't have permission to include file]",)
    273280            else:
    274281                return '' # Fail silently for invalid includes.
    275282        try:
     
    280287            output = ''
    281288        if self.parsed:
    282289            try:
    283                 t = Template(output, name=self.filepath)
    284                 return t.render(context)
     290                return Template(output, name=self.filepath).iter_render(context)
    285291            except TemplateSyntaxError, e:
    286292                if settings.DEBUG:
    287293                    return "[Included template had syntax error: %s]" % e
    288294                else:
    289295                    return '' # Fail silently for invalid included templates.
    290         return output
     296        return (output,)
    291297
    292298class LoadNode(Node):
    293     def render(self, context):
    294         return ''
     299    def iter_render(self, context):
     300        return ()
    295301
    296302class NowNode(Node):
    297303    def __init__(self, format_string):
    298304        self.format_string = format_string
    299305
     306    def iter_render(self, context):
     307        return (self.render(context),)
     308
    300309    def render(self, context):
    301310        from datetime import datetime
    302311        from django.utils.dateformat import DateFormat
     
    325334    def __init__(self, tagtype):
    326335        self.tagtype = tagtype
    327336
     337    def iter_render(self, context):
     338        return (self.render(context),)
     339
    328340    def render(self, context):
    329341        return self.mapping.get(self.tagtype, '')
    330342
     
    334346        self.args = args
    335347        self.kwargs = kwargs
    336348
    337     def render(self, context):
     349    def iter_render(self, context):
    338350        from django.core.urlresolvers import reverse, NoReverseMatch
    339351        args = [arg.resolve(context) for arg in self.args]
    340352        kwargs = dict([(k, v.resolve(context)) for k, v in self.kwargs.items()])
    341353        try:
    342             return reverse(self.view_name, args=args, kwargs=kwargs)
     354            return (reverse(self.view_name, args=args, kwargs=kwargs),)
    343355        except NoReverseMatch:
    344356            try:
    345357                project_name = settings.SETTINGS_MODULE.split('.')[0]
    346358                return reverse(project_name + '.' + self.view_name, args=args, kwargs=kwargs)
    347359            except NoReverseMatch:
    348                 return ''
     360                return ()
    349361
    350362class WidthRatioNode(Node):
    351363    def __init__(self, val_expr, max_expr, max_width):
     
    353365        self.max_expr = max_expr
    354366        self.max_width = max_width
    355367
     368    def iter_render(self, context):
     369        return (self.render(context),)
     370
    356371    def render(self, context):
    357372        try:
    358373            value = self.val_expr.resolve(context)
     
    376391    def __repr__(self):
    377392        return "<WithNode>"
    378393
    379     def render(self, context):
     394    def iter_render(self, context):
    380395        val = self.var.resolve(context)
    381396        context.push()
    382397        context[self.name] = val
    383         output = self.nodelist.render(context)
     398        for chunk in self.nodelist.iter_render(context):
     399            yield chunk
    384400        context.pop()
    385         return output
    386401
    387402#@register.tag
    388403def comment(parser, token):
  • django/template/loader_tags.py

    === django/template/loader_tags.py
    ==================================================================
     
    1515    def __repr__(self):
    1616        return "<Block Node: %s. Contents: %r>" % (self.name, self.nodelist)
    1717
    18     def render(self, context):
     18    def iter_render(self, context):
    1919        context.push()
    2020        # Save context in case of block.super().
    2121        self.context = context
    2222        context['block'] = self
    23         result = self.nodelist.render(context)
     23        for chunk in self.nodelist.iter_render(context):
     24            yield chunk
    2425        context.pop()
    25         return result
    2626
    2727    def super(self):
    2828        if self.parent:
     
    5757        except TemplateDoesNotExist:
    5858            raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
    5959        else:
    60             return get_template_from_string(source, origin, parent)
     60            return get_template_from_string(source, origin)
    6161
    62     def render(self, context):
     62    def iter_render(self, context):
    6363        compiled_parent = self.get_parent(context)
    6464        parent_is_child = isinstance(compiled_parent.nodelist[0], ExtendsNode)
    6565        parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
     
    7979                parent_block.parent = block_node.parent
    8080                parent_block.add_parent(parent_block.nodelist)
    8181                parent_block.nodelist = block_node.nodelist
    82         return compiled_parent.render(context)
     82        return compiled_parent.iter_render(context)
    8383
    8484class ConstantIncludeNode(Node):
    8585    def __init__(self, template_path):
     
    9191                raise
    9292            self.template = None
    9393
    94     def render(self, context):
     94    def iter_render(self, context):
    9595        if self.template:
    96             return self.template.render(context)
    97         else:
    98             return ''
     96            return self.template.iter_render(context)
     97        return ()
    9998
    10099class IncludeNode(Node):
    101100    def __init__(self, template_name):
    102101        self.template_name = template_name
    103102
    104     def render(self, context):
     103    def iter_render(self, context):
    105104        try:
    106105            template_name = resolve_variable(self.template_name, context)
    107106            t = get_template(template_name)
    108             return t.render(context)
     107            return t.iter_render(context)
    109108        except TemplateSyntaxError, e:
    110109            if settings.TEMPLATE_DEBUG:
    111110                raise
    112             return ''
     111            return ()
    113112        except:
    114             return '' # Fail silently for invalid included templates.
     113            return () # Fail silently for invalid included templates.
    115114
    116115def do_block(parser, token):
    117116    """
  • django/template/loader.py

    === django/template/loader.py
    ==================================================================
     
    7676    Returns a compiled Template object for the given template name,
    7777    handling template inheritance recursively.
    7878    """
    79     source, origin = find_template_source(template_name)
    80     template = get_template_from_string(source, origin, template_name)
    81     return template
     79    return get_template_from_string(*find_template_source(template_name))
    8280
    83 def get_template_from_string(source, origin=None, name=None):
     81def get_template_from_string(source, origin=None):
    8482    """
    8583    Returns a compiled Template object for the given template code,
    8684    handling template inheritance recursively.
    8785    """
    88     return Template(source, origin, name)
     86    return Template(source, origin)
    8987
    90 def render_to_string(template_name, dictionary=None, context_instance=None):
     88def _render_setup(template_name, dictionary=None, context_instance=None):
    9189    """
    92     Loads the given template_name and renders it with the given dictionary as
    93     context. The template_name may be a string to load a single template using
    94     get_template, or it may be a tuple to use select_template to find one of
    95     the templates in the list. Returns a string.
     90    Common setup code for render_to_string and render_to_iter.
    9691    """
    97     dictionary = dictionary or {}
     92    if dictionary is None:
     93        dictionary = {}
    9894    if isinstance(template_name, (list, tuple)):
    9995        t = select_template(template_name)
    10096    else:
     
    10399        context_instance.update(dictionary)
    104100    else:
    105101        context_instance = Context(dictionary)
    106     return t.render(context_instance)
     102    return t, context_instance
    107103
     104def render_to_string(template_name, dictionary=None, context_instance=None):
     105    """
     106    Loads the given template_name and renders it with the given dictionary as
     107    context. The template_name may be a string to load a single template using
     108    get_template, or it may be a tuple to use select_template to find one of
     109    the templates in the list. Returns a string.
     110    """
     111    t, c = _render_setup(template_name, dictionary=dictionary, context_instance=context_instance)
     112    return t.render(c)
     113
     114def render_to_iter(template_name, dictionary=None, context_instance=None):
     115    """
     116    Loads the given template_name and renders it with the given dictionary as
     117    context. The template_name may be a string to load a single template using
     118    get_template, or it may be a tuple to use select_template to find one of
     119    the templates in the list. Returns a string.
     120    """
     121    t, c = _render_setup(template_name, dictionary=dictionary, context_instance=context_instance)
     122    return t.iter_render(c)
     123
     124
    108125def select_template(template_name_list):
    109126    "Given a list of template names, returns the first that can be loaded."
    110127    for template_name in template_name_list:
  • tests/modeltests/multiple_databases/__init__.py

    === tests/modeltests/multiple_databases/__init__.py
    ==================================================================
     
     1pass
  • tests/modeltests/multiple_databases/models.py

    === 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(maxlength=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(maxlength=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(maxlength=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(maxlength=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(maxlength=20)
     68    model = models.CharField(maxlength=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/modeltests/multiple_databases
    ___________________________________________________________________
    Name: svn:ignore
     +*.pyc
     +
    
    === tests/regressiontests/manager_db/__init__.py
    ==================================================================
    === tests/regressiontests/manager_db/tests.py
    ==================================================================
     
     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.backend.quote_name
     14        assert db.get_creation_module
     15
     16if __name__ == '__main__':
     17    unittest.main()
  • tests/regressiontests/manager_db/models.py

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

    Property changes on: tests/regressiontests/manager_db
    ___________________________________________________________________
    Name: svn:ignore
     +*.pyc
     +
    
    === tests/regressiontests/thread_isolation/__init__.py
    ==================================================================
    === tests/regressiontests/thread_isolation/tests.py
    ==================================================================
     
     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

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

    Property changes on: tests/regressiontests/thread_isolation
    ___________________________________________________________________
    Name: svn:ignore
     +*.pyc
     +
    
    
    Property changes on: tests/regressiontests/initial_sql_regress/sql
    ___________________________________________________________________
    Name: svn:ignore
     +*.pyc
     +
    
    === tests/regressiontests/ansi_sql/sql/car.sql
    ==================================================================
     
     1insert into ansi_sql_car (make, model, year, condition)
     2       values ('Chevy', 'Impala', 1966, 'mint');
  • tests/regressiontests/ansi_sql/models.py

    Property changes on: tests/regressiontests/ansi_sql/sql
    ___________________________________________________________________
    Name: svn:ignore
     +*.pyc
     +
    
    === tests/regressiontests/ansi_sql/__init__.py
    ==================================================================
    === tests/regressiontests/ansi_sql/models.py
    ==================================================================
     
     1"""
     2>>> from django.db.backends.ansi import sql
     3
     4# so we can test with a predicatable constraint setting
     5>>> real_cnst = Mod._default_manager.db.backend.supports_constraints
     6>>> Mod._default_manager.db.backend.supports_constraints = True
     7   
     8# generate create sql
     9>>> builder = sql.SchemaBuilder()
     10>>> builder.get_create_table(Car)
     11([BoundStatement('CREATE TABLE "ansi_sql_car" (...);')], {})
     12>>> builder.models_already_seen
     13Set([<class 'regressiontests.ansi_sql.models.Car'>])
     14>>> builder.models_already_seen = set()
     15
     16# test that styles are used
     17>>> builder.get_create_table(Car, style=mockstyle())
     18([BoundStatement('SQL_KEYWORD(CREATE TABLE) SQL_TABLE("ansi_sql_car") (...SQL_FIELD("id")...);')], {})
     19
     20# test pending relationships
     21>>> builder.models_already_seen = set()
     22>>> builder.get_create_table(Mod)
     23([BoundStatement('CREATE TABLE "ansi_sql_mod" (..."car_id" integer NOT NULL,...);')], {<class 'regressiontests.ansi_sql.models.Car'>: [(<class 'regressiontests.ansi_sql.models.Mod'>, <django.db.models.fields.related.ForeignKey...>)]})
     24>>> builder.models_already_seen = set()
     25>>> builder.get_create_table(Car)
     26([BoundStatement('CREATE TABLE "ansi_sql_car" (...);')], {})
     27>>> builder.get_create_table(Mod)
     28([BoundStatement('CREATE TABLE "ansi_sql_mod" (..."car_id" integer NOT NULL REFERENCES "ansi_sql_car" ("id"),...);')], {})
     29
     30# test many-many
     31>>> builder.get_create_table(Collector)
     32([BoundStatement('CREATE TABLE "ansi_sql_collector" (...);')], {})
     33>>> builder.get_create_many_to_many(Collector)
     34{<class 'regressiontests.ansi_sql.models.Car'>: [BoundStatement('CREATE TABLE "ansi_sql_collector_cars" (...);')]}
     35
     36# test indexes
     37>>> builder.get_create_indexes(Car)
     38[]
     39>>> builder.get_create_indexes(Mod)
     40[BoundStatement('CREATE INDEX ... ON "ansi_sql_mod" ("car_id");'), BoundStatement('CREATE INDEX ... ON "ansi_sql_mod" ("part");')]
     41>>> builder.get_create_indexes(Collector)
     42[]
     43
     44# test initial data
     45# patch builder so that it looks for initial data where we want it to
     46# >>> builder.get_initialdata_path = othertests_sql
     47>>> builder.get_initialdata(Car)
     48[BoundStatement("insert into ansi_sql_car (...)...values (...);...")]
     49
     50# test drop
     51>>> builder.get_drop_table(Mod)
     52[BoundStatement('DROP TABLE "ansi_sql_mod";')]
     53>>> builder.get_drop_table(Mod, cascade=True)
     54[BoundStatement('DROP TABLE "ansi_sql_mod";')]
     55>>> builder.get_drop_table(Car)
     56[BoundStatement('DROP TABLE "ansi_sql_car";')]
     57
     58# drop with cascade
     59>>> builder.tables = ['ansi_sql_car', 'ansi_sql_mod', 'ansi_sql_collector']
     60>>> Mod._default_manager.db.backend.supports_constraints = False
     61>>> Mod._default_manager.db.backend.supports_constraints
     62False
     63>>> Car._default_manager.db.backend.supports_constraints
     64False
     65>>> builder.get_drop_table(Car, cascade=True)
     66[BoundStatement('DROP TABLE "ansi_sql_car";')]
     67>>> Mod._default_manager.db.backend.supports_constraints = True
     68>>> Mod._default_manager.db.backend.supports_constraints
     69True
     70>>> Car._default_manager.db.backend.supports_constraints
     71True
     72>>> builder.get_drop_table(Car, cascade=True)
     73[BoundStatement('DROP TABLE "ansi_sql_car";'), BoundStatement('ALTER TABLE "ansi_sql_mod" ...')]
     74>>> builder.get_drop_table(Collector)
     75[BoundStatement('DROP TABLE "ansi_sql_collector";')]
     76>>> builder.get_drop_table(Collector, cascade=True)
     77[BoundStatement('DROP TABLE "ansi_sql_collector";'), BoundStatement('DROP TABLE "ansi_sql_collector_cars";')]
     78>>> Mod._default_manager.db.backend.supports_constraints = real_cnst
     79
     80"""
     81#import os
     82#import sys
     83#from django.conf import settings
     84#from django.core.management import install
     85from django.db import models
     86#from django.db.models import loading
     87
     88
     89# For Python 2.3
     90if not hasattr(__builtins__, 'set'):
     91    from sets import Set as set
     92
     93
     94# test models
     95class Car(models.Model):
     96    make = models.CharField(maxlength=32)
     97    model = models.CharField(maxlength=32)
     98    year = models.IntegerField()
     99    condition = models.CharField(maxlength=32)
     100
     101       
     102class Collector(models.Model):
     103    name = models.CharField(maxlength=32)
     104    cars = models.ManyToManyField(Car)
     105
     106       
     107class Mod(models.Model):
     108    car = models.ForeignKey(Car)
     109    part = models.CharField(maxlength=32, db_index=True)
     110    description = models.TextField()
     111
     112
     113class mockstyle:
     114    """mock style that wraps text in STYLE(text), for testing"""
     115    def __getattr__(self, attr):
     116        if attr in ('ERROR', 'ERROR_OUTPUT', 'SQL_FIELD', 'SQL_COLTYPE',
     117                    'SQL_KEYWORD', 'SQL_TABLE'):
     118            return lambda text: "%s(%s)" % (attr, text)
     119
     120       
     121# def othertests_sql(mod):
     122#     """Look in othertests/sql for sql initialdata"""
     123#     return os.path.normpath(os.path.join(os.path.dirname(__file__), 'sql'))
     124
     125
     126# # install my models and force myself into the registry of apps and models
     127# # (without this, references and such to/from the models installed here
     128# # won't be picked up in get_models(), since get_models() looks only at
     129# # models from apps in INSTALLED_APPS, and the model and app lookup rules
     130# # enforce a module structure that this test file can't follow)
     131# Car.objects.install()
     132# Collector.objects.install()
     133# Mod.objects.install()
     134# loading.get_apps()
     135# loading._app_list.append(sys.modules[__name__])
     136
     137# # model lookup only works for pk.models, so fake up my module name
     138# __name__ = 'othertests.ansi_sql.models'
  • tests/regressiontests/request_isolation/tests.py

    Property changes on: tests/regressiontests/ansi_sql
    ___________________________________________________________________
    Name: svn:ignore
     +*.pyc
     +
    
    === tests/regressiontests/request_isolation/__init__.py
    ==================================================================
    === tests/regressiontests/request_isolation/tests.py
    ==================================================================
     
     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

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

    Property changes on: tests/regressiontests/request_isolation
    ___________________________________________________________________
    Name: svn:ignore
     +*.pyc
     +
    
    === tests/regressiontests/manager_schema_manipulation/__init__.py
    ==================================================================
    === tests/regressiontests/manager_schema_manipulation/tests.py
    ==================================================================
     
     1"""
     2# Django uses a model's default manager to perform schema
     3# manipulations such as creating or dropping the model's table.
     4
     5>>> from django.db import models
     6>>> from django.conf import settings
     7>>> import copy
     8
     9# save copy of settings so we can restore it later
     10>>> odb = copy.deepcopy(settings.OTHER_DATABASES)
     11>>> settings.OTHER_DATABASES['django_msm_test_db_a'] = { 'MODELS': ['msm.PA', 'msm.P', 'msm.PC']}
     12>>> settings.OTHER_DATABASES['django_msm_test_db_b'] = {'MODELS': ['msm.QA', 'msm.QB', 'msm.QC', 'msm.QD']}
     13
     14# default connection
     15>>> class DA(models.Model):
     16...     name = models.CharField(maxlength=20)
     17...     
     18...     def __str__(self):
     19...         return self.name
     20   
     21# connection a
     22>>> class PA(models.Model):
     23...     name = models.CharField(maxlength=20)
     24...     # This creates a cycle in the dependency graph
     25...     c = models.ForeignKey('PC', null=True)
     26...     
     27...     def __str__(self):
     28...         return self.name
     29...     
     30...     class Meta:
     31...         app_label = 'msm'
     32
     33>>> class PB(models.Model):
     34...     name = models.CharField(maxlength=20)
     35...     a = models.ForeignKey(PA)
     36...     
     37...     def __str__(self):
     38...         return self.name
     39...     
     40...     class Meta:
     41...         app_label = 'msm'
     42
     43>>> class PC(models.Model):
     44...     name = models.CharField(maxlength=20)
     45...     b = models.ForeignKey(PB)
     46...     
     47...     def __str__(self):
     48...         return self.name
     49...     
     50...     class Meta:
     51...         app_label = 'msm'
     52   
     53# connection b
     54>>> class QA(models.Model):
     55...     name = models.CharField(maxlength=20)
     56...     
     57...     def __str__(self):
     58...         return self.name
     59...     
     60...     class Meta:
     61...         app_label = 'msm'
     62
     63>>> class QB(models.Model):
     64...     name = models.CharField(maxlength=20)
     65...     a = models.ForeignKey(QA)
     66...     
     67...     def __str__(self):
     68...         return self.name
     69...     
     70...     class Meta:
     71...         app_label = 'msm'
     72
     73# many-many
     74>>> class QC(models.Model):
     75...     name = models.CharField(maxlength=20)
     76...     
     77...     def __str__(self):
     78...         return self.name
     79...     
     80...     class Meta:
     81...         app_label = 'msm'
     82
     83>>> class QD(models.Model):
     84...     name = models.CharField(maxlength=20)
     85...     qcs = models.ManyToManyField(QC)
     86...     
     87...     def __str__(self):
     88...         return self.name
     89...     
     90...     class Meta:
     91...         app_label = 'msm'
     92
     93# Using the manager, models can be installed individually, whether they
     94# use the default connection or a named connection.
     95
     96>>> DA.objects.install()
     97{}
     98>>> QA.objects.install()
     99{}
     100>>> QB.objects.install()
     101{}
     102>>> DA.objects.all()
     103[]
     104>>> list(QA.objects.all())
     105[]
     106>>> list(QB.objects.all())
     107[]
     108>>> QA(name="something").save()
     109>>> QA.objects.all()
     110[<QA: something>]
     111
     112# The `install()` method returns a tuple, the first element of which is a
     113# list of statements that were executed, and the second, pending
     114# statements that could not be executed because (for instance) they are
     115# meant to establish foreign key relationships to tables that don't
     116# exist. These are bound to the model's connection and should
     117# be executed after all models in the app have been installed. The pending
     118# statments are returned as a dict keyed by the model which must be installed
     119# before the pending statements can be installed.
     120
     121# NOTE: pretend db supports constraints for this test
     122>>> real_cnst = PA._default_manager.db.backend.supports_constraints
     123>>> PA._default_manager.db.backend.supports_constraints = True
     124>>> result = PA.objects.install()
     125>>> result
     126{<class 'regressiontests.manager_schema_manipulation.tests.PC'>: [(<class 'regressiontests.manager_schema_manipulation.tests.PA'>, <django.db.models.fields.related.ForeignKey ...>)]}
     127
     128# NOTE: restore real constraint flag
     129>>> PA._default_manager.db.backend.supports_constraints = real_cnst
     130
     131# Models with many-many relationships may also have pending statement
     132# lists. Like other pending statements, these should be executed after
     133# all models in the app have been installed. If the related table's model
     134# has already been created, then there will be no pending list.
     135
     136>>> QC.objects.install()
     137{}
     138>>> QD.objects.install()
     139{}
     140
     141# Finally, restore the original settings
     142>>> settings.OTHER_DATABASES = odb
     143"""
  • tests/runtests.py

    === tests/regressiontests/manager_schema_manipulation/models.py
    ==================================================================
    
    Property changes on: tests/regressiontests/manager_schema_manipulation
    ___________________________________________________________________
    Name: svn:ignore
     +*.pyc
     +
    
    === tests/runtests.py
    ==================================================================
     
    1212TEST_TEMPLATE_DIR = 'templates'
    1313
    1414CONTRIB_DIR = os.path.dirname(contrib.__file__)
     15
     16TEST_DATABASES = ('_a', '_b')
     17
     18TEST_DATABASE_MODELS = {
     19    '_a': [ 'multiple_databases.Artist',
     20            'multiple_databases.Opus' ],
     21    '_b': [ 'multiple_databases.Widget',
     22            'multiple_databases.DooHickey' ]
     23}
     24
     25
    1526MODEL_TEST_DIR = os.path.join(os.path.dirname(__file__), MODEL_TESTS_DIR_NAME)
    1627REGRESSION_TEST_DIR = os.path.join(os.path.dirname(__file__), REGRESSION_TESTS_DIR_NAME)
    1728
     
    8697    # Redirect some settings for the duration of these tests.
    8798    settings.TEST_DATABASE_NAME = TEST_DATABASE_NAME
    8899    settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS
     100    settings.TEST_DATABASES = TEST_DATABASES
     101    settings.TEST_DATABASE_MODELS = TEST_DATABASE_MODELS
    89102    settings.ROOT_URLCONF = 'urls'
    90103    settings.TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), TEST_TEMPLATE_DIR),)
    91104    settings.USE_I18N = True
  • docs/settings.txt

    Property changes on: tests/templates
    ___________________________________________________________________
    Name: svn:ignore
     +*.pyc
     +
    
    === docs/settings.txt
    ==================================================================
     
    640640See `allowed date format strings`_. See also DATE_FORMAT, DATETIME_FORMAT,
    641641TIME_FORMAT and YEAR_MONTH_FORMAT.
    642642
     643OTHER_DATABASES
     644---------------
     645
     646Default: ``{}``
     647
     648Other database connections to use in addition to the default connection. See the `multiple database support docs`_.
     649
    643650PREPEND_WWW
    644651-----------
    645652
     
    966973
    967974.. _cache docs: ../cache/
    968975.. _middleware docs: ../middleware/
     976.. _multiple database support docs: ../multiple_database_support/
    969977.. _session docs: ../sessions/
    970978.. _See available choices: http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
    971979.. _template documentation: ../templates_python/
  • docs/multiple_database_support.txt

    === 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/templates_python.txt

    === docs/templates_python.txt
    ==================================================================
     
    219219
    220220    While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool,
    221221    it is a bad idea to turn it on as a 'development default'.
    222    
     222
    223223    Many templates, including those in the Admin site, rely upon the
    224224    silence of the template system when a non-existent variable is
    225225    encountered. If you assign a value other than ``''`` to
    226226    ``TEMPLATE_STRING_IF_INVALID``, you will experience rendering
    227227    problems with these templates and sites.
    228    
     228
    229229    Generally, ``TEMPLATE_STRING_IF_INVALID`` should only be enabled
    230230    in order to debug a specific template problem, then cleared
    231231    once debugging is complete.
     
    693693
    694694When Django compiles a template, it splits the raw template text into
    695695''nodes''. Each node is an instance of ``django.template.Node`` and has
    696 a ``render()`` method. A compiled template is, simply, a list of ``Node``
    697 objects. When you call ``render()`` on a compiled template object, the template
    698 calls ``render()`` on each ``Node`` in its node list, with the given context.
    699 The results are all concatenated together to form the output of the template.
     696either a ``render()`` or ``iter_render()`` method. A compiled template is,
     697simply, a list of ``Node`` objects. When you call ``render()`` on a compiled
     698template object, the template calls ``render()`` on each ``Node`` in its node
     699list, with the given context. The results are all concatenated together to
     700form the output of the template.
    700701
    701702Thus, to define a custom template tag, you specify how the raw template tag is
    702703converted into a ``Node`` (the compilation function), and what the node's
    703 ``render()`` method does.
     704``render()`` or ``iter_render()`` method does.
    704705
    705706Writing the compilation function
    706707~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     
    770771~~~~~~~~~~~~~~~~~~~~
    771772
    772773The second step in writing custom tags is to define a ``Node`` subclass that
    773 has a ``render()`` method.
     774has a ``render()`` method (we will discuss the ``iter_render()`` alternative
     775in `Improving rendering speed`_, below).
    774776
    775777Continuing the above example, we need to define ``CurrentTimeNode``::
    776778
     
    874876        def __init__(self, date_to_be_formatted, format_string):
    875877            self.date_to_be_formatted = date_to_be_formatted
    876878            self.format_string = format_string
    877        
     879
    878880        def render(self, context):
    879881            try:
    880882                actual_date = resolve_variable(self.date_to_be_formatted, context)
     
    11751177
    11761178.. _configuration:
    11771179
     1180Improving rendering speed
     1181~~~~~~~~~~~~~~~~~~~~~~~~~
     1182
     1183For most practical purposes, the ``render()`` method on a ``Node`` will be
     1184sufficient and the simplest way to implement a new tag. However, if your
     1185template tag is expected to produce large strings via ``render()``, you can
     1186speed up the rendering process (and reduce memory usage) using iterative
     1187rendering via the ``iter_render()`` method.
     1188
     1189The ``iter_render()`` method should either be an iterator that yields string
     1190chunks, one at a time, or a method that returns a sequence of string chunks.
     1191The template renderer will join the successive chunks together when creating
     1192the final output. The improvement over the ``render()`` method here is that
     1193you do not need to create one large string containing all the output of the
     1194``Node``, instead you can produce the output in smaller chunks.
     1195
     1196By way of example, here's a trivial ``Node`` subclass that simply returns the
     1197contents of a file it is given::
     1198
     1199    class FileNode(Node):
     1200        def __init__(self, filename):
     1201            self.filename = filename
     1202
     1203        def iter_render(self):
     1204            for line in file(self.filename):
     1205                yield line
     1206
     1207For very large files, the full file contents will never be read entirely into
     1208memory when this tag is used, which is a useful optimisation.
     1209
     1210If you define an ``iter_render()`` method on your ``Node`` subclass, you do
     1211not need to define a ``render()`` method. The reverse is true as well: the
     1212default ``Node.iter_render()`` method will call your ``render()`` method if
     1213necessary. A useful side-effect of this is that you can develop a new tag
     1214using ``render()`` and producing all the output at once, which is easy to
     1215debug. Then you can rewrite the method as an iterator, rename it to
     1216``iter_render()`` and everything will still work.
     1217
     1218It is compulsory, however, to define *either* ``render()`` or ``iter_render()``
     1219in your subclass. If you omit them both, a ``TypeError`` will be raised when
     1220the code is imported.
     1221
    11781222Configuring the template system in standalone mode
    11791223==================================================
    11801224
     
    12061250
    12071251.. _settings file: ../settings/#using-settings-without-the-django-settings-module-environment-variable
    12081252.. _settings documentation: ../settings/
     1253
Back to Top