MultipleDatabaseSupport: p4.diff

File p4.diff, 36.2 KB (added by jpellerin@…, 18 years ago)

Current (incomplete) patch as of 2006-06-08

  • django/db/models/base.py

    === django/db/models/base.py
    ==================================================================
     
    3838                new_class._meta.parents.extend(base._meta.parents)
    3939
    4040        model_module = sys.modules[new_class.__module__]
    41 
     41       
    4242        if getattr(new_class._meta, 'app_label', None) is None:
    4343            # Figure out the app_label by looking one level up.
    4444            # For 'django.contrib.sites.models', this would be 'sites'.
     
    149149        dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self)
    150150
    151151        non_pks = [f for f in self._meta.fields if not f.primary_key]
    152         cursor = connection.cursor()
     152        cursor = self._meta.connection.cursor()
    153153
    154154        # First, try an UPDATE. If that doesn't update anything, do an INSERT.
    155155        pk_val = self._get_pk_val()
     
    362362        rel = rel_field.rel.to
    363363        m2m_table = rel_field.m2m_db_table()
    364364        this_id = self._get_pk_val()
    365         cursor = connection.cursor()
     365        cursor = self._meta.connection.cursor()
    366366        cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
    367367            (backend.quote_name(m2m_table),
    368368            backend.quote_name(rel_field.m2m_column_name())), [this_id])
     
    380380# ORDERING METHODS #########################
    381381
    382382def method_set_order(ordered_obj, self, id_list):
     383    connection_info = ordered_obj.connection_info
     384    connection = info.connection
     385    backend = info.backend
     386   
    383387    cursor = connection.cursor()
    384388    # Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s"
    385389    sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \
     
    391395    transaction.commit_unless_managed()
    392396
    393397def method_get_order(ordered_obj, self):
     398    connection_info = ordered_obj.connection_info
     399    connection = info.connection
     400    backend = info.backend
    394401    cursor = connection.cursor()
    395402    # Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order"
    396403    sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \
  • django/db/models/manager.py

    === django/db/models/manager.py
    ==================================================================
     
    9595    def values(self, *args, **kwargs):
    9696        return self.get_query_set().values(*args, **kwargs)
    9797
     98    #######################
     99    # SCHEMA MANIPULATION #
     100    #######################
     101
     102    def install(self, initial_data=False):
     103        """Install my model's table, indexes and (if requested) initial data.
     104
     105        Returns a 3-tuple of the model and lists of statements executed and
     106        statements pending. Pending statements are those that could
     107        not yet be executed, such as foreign key constraints for
     108        tables that don't exist at install time.
     109        """
     110        creator = self.model._meta.connection_info.get_creation_module()
     111        create, pending = creator.get_create_table(self.model)
     112        create += creator.get_create_indexes(self.model)
     113        if initial_data:
     114            create += creator.get_initialdata(self.model)
     115
     116        executed = []
     117        for statement in create:
     118            statement.execute()
     119        return (self.model, create, pending)
     120
     121    def load_initial_data(self):
     122        """Load initial data for my model into the database."""
     123        pass
     124
     125    def drop(self):
     126        """Drop my model's table."""
     127        pass
     128
     129    # Future...
     130   
     131    def add_column(self, column):
     132        """Add a column to my model's table"""
     133        pass
     134
     135    def drop_column(self, column):
     136        """Drop a column from my model's table"""
     137        pass
     138       
     139
    98140class ManagerDescriptor(object):
    99141    # This class ensures managers aren't accessible via model instances.
    100142    # For example, Poll.objects works, but poll_obj.objects raises AttributeError.
  • 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
     
    1112# Calculate the verbose_name by converting from InitialCaps to "lowercase with spaces".
    1213get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip()
    1314
    14 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
     15DEFAULT_NAMES = ('verbose_name', 'db_connection', 'db_table', 'ordering',
    1516                 'unique_together', 'permissions', 'get_latest_by',
    1617                 'order_with_respect_to', 'app_label')
    1718
     
    2021        self.fields, self.many_to_many = [], []
    2122        self.module_name, self.verbose_name = None, None
    2223        self.verbose_name_plural = None
     24        self.db_connection = None
    2325        self.db_table = ''
    2426        self.ordering = []
    2527        self.unique_together =  []
     
    5658                raise TypeError, "'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys())
    5759        else:
    5860            self.verbose_name_plural = self.verbose_name + 's'
     61        #
    5962        del self.meta
    6063
    6164    def _prepare(self, model):
     
    8891    def __repr__(self):
    8992        return '<Options for %s>' % self.object_name
    9093
     94    def get_connection_info(self):
     95        if self.db_connection:
     96            return connections[self.db_connection]
     97        return connection_info
     98    connection_info = property(get_connection_info)
     99           
     100    def get_connection(self):
     101        """Get the database connection for this object's model"""
     102        return self.get_connection_info().connection
     103    connection = property(get_connection)
     104   
    91105    def get_field(self, name, many_to_many=True):
    92106        "Returns the requested field by name. Raises FieldDoesNotExist on error."
    93107        to_search = many_to_many and (self.fields + self.many_to_many) or self.fields
  • django/db/models/loading.py

    === django/db/models/loading.py
    ==================================================================
     
    88_app_list = None # Cache of installed apps.
    99_app_models = {} # Dictionary of models against app label
    1010                 # Each value is a dictionary of model name: model class
    11 
     11_app_model_order = {} # Dictionary of models against app label
     12                      # Each value is a list of model names, in the order in
     13                      # which the models were created
    1214def get_apps():
    1315    "Returns a list of all installed modules that contain models."
    1416    global _app_list
     
    3537            return __import__(app_name, '', '', ['models']).models
    3638    raise ImproperlyConfigured, "App with label %s could not be found" % app_label
    3739
    38 def get_models(app_mod=None):
     40def get_models(app_mod=None, creation_order=False):
    3941    """
    4042    Given a module containing models, returns a list of the models. Otherwise
    41     returns a list of all installed models.
     43    returns a list of all installed models. In either case, if creation_order
     44    is true, return the models sorted into the same order in which they
     45    were created.
    4246    """
    4347    app_list = get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
    4448    if app_mod:
    45         return _app_models.get(app_mod.__name__.split('.')[-2], {}).values()
     49        app_label = app_mod.__name__.split('.')[-2]
     50        app_models = _app_models.get(app_label, {})
     51        if creation_order:
     52            return [ app_models[name]
     53                     for name in _app_model_order.get(app_label, []) ]
     54        return app_models.values()
    4655    else:
    4756        model_list = []
    4857        for app_mod in app_list:
     
    7584        model_name = model._meta.object_name.lower()
    7685        model_dict = _app_models.setdefault(app_label, {})
    7786        model_dict[model_name] = model
     87        model_list = _app_model_order.setdefault(app_label, [])
     88        model_list.append(model_name)
  • django/db/models/query.py

    === django/db/models/query.py
    ==================================================================
     
    1 from django.db import backend, connection, transaction
     1from django.db import backend, connection, connections, transaction
    22from django.db.models.fields import DateField, FieldDoesNotExist
    33from django.db.models import signals
    44from django.dispatch import dispatcher
     
    158158        # undefined, so we convert it to a list of tuples.
    159159        extra_select = self._select.items()
    160160
    161         cursor = connection.cursor()
     161        cursor = self.model._meta.connection.cursor()
    162162        select, sql, params = self._get_sql_clause()
    163163        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
    164164        fill_cache = self._select_related
     
    178178
    179179    def count(self):
    180180        "Performs a SELECT COUNT() and returns the number of records as an integer."
     181
     182        info = self.model._meta.connection_info
     183        backend = info.backend
     184        connection = info.connection
     185       
    181186        counter = self._clone()
    182187        counter._order_by = ()
    183188        counter._offset = None
     
    505510            columns = [f.column for f in self.model._meta.fields]
    506511            field_names = [f.attname for f in self.model._meta.fields]
    507512
     513        info = self.model._meta.connection_info
     514        backend = info.backend
     515        connection = info.connection
    508516        cursor = connection.cursor()
    509517        select, sql, params = self._get_sql_clause()
    510518        select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
     
    524532class DateQuerySet(QuerySet):
    525533    def iterator(self):
    526534        from django.db.backends.util import typecast_timestamp
     535
     536        info = self.model._meta.connection_info
     537        backend = info.backend
     538        connection = info.connection
     539       
    527540        self._order_by = () # Clear this because it'll mess things up otherwise.
    528541        if self._field.null:
    529542            self._where.append('%s.%s IS NOT NULL' % \
     
    616629        where2 = ['(NOT (%s))' % " AND ".join(where)]
    617630        return tables, joins, where2, params
    618631
    619 def get_where_clause(lookup_type, table_prefix, field_name, value):
     632def get_where_clause(opts, lookup_type, table_prefix, field_name, value):
     633    backend = opts.connection_info.backend
     634   
    620635    if table_prefix.endswith('.'):
    621636        table_prefix = backend.quote_name(table_prefix[:-1])+'.'
    622637    field_name = backend.quote_name(field_name)
     
    745760    intermediate_table = None
    746761    join_required = False
    747762
     763    info = current_opts.connection_info
     764    backend = info.backend
     765    connection = info.connection
     766
    748767    name = path.pop(0)
    749768    # Has the primary key been requested? If so, expand it out
    750769    # to be the name of the current class' primary key
     
    872891        else:
    873892            column = field.column
    874893
    875         where.append(get_where_clause(clause, current_table + '.', column, value))
     894        where.append(get_where_clause(current_opts, clause, current_table + '.', column, value))
    876895        params.extend(field.get_db_prep_lookup(clause, value))
    877896
    878897    return tables, joins, where, params
     
    882901    ordered_classes = seen_objs.keys()
    883902    ordered_classes.reverse()
    884903
    885     cursor = connection.cursor()
    886904
    887905    for cls in ordered_classes:
     906
     907        info = cls._meta.connection_info
     908        backend = info.backend
     909        connection = info.connection
     910        cursor = connection.cursor()
     911       
    888912        seen_objs[cls] = seen_objs[cls].items()
    889913        seen_objs[cls].sort()
    890914
     
    919943
    920944    # Now delete the actual data
    921945    for cls in ordered_classes:
     946
     947        info = cls._meta.connection_info
     948        backend = info.backend
     949        connection = info.connection
     950        cursor = connection.cursor()
     951
    922952        seen_objs[cls].reverse()
    923953        pk_list = [pk for pk,instance in seen_objs[cls]]
    924954        for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE):
  • 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
    56__all__ = ('backend', 'connection', 'DatabaseError')
     
    78if not settings.DATABASE_ENGINE:
    89    settings.DATABASE_ENGINE = 'dummy'
    910
    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. vailable 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.
     11class ConnectionInfo(object):
     12    """Encapsulates all information about a db connection:
     13     - connection
     14     - DatabaseError
     15     - backend
     16     - get_introspection_module
     17     - get_creation_module
     18     - runshell
     19    """
     20    def __init__(self, connection, DatabaseError, backend,
     21                 get_introspection_module, get_creation_module, runshell):
     22        self.connection = connection
     23        self.DatabaseError = DatabaseError
     24        self.backend = backend
     25        self.get_introspection_module = get_introspection_module
     26        self.get_creation_module = get_creation_module
     27        self.runshell = runshell
    2528
    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()
     29    def __repr__(self):
     30        return "Connection: %r (ENGINE=%s NAME=%s)" \
     31               % (self.connection,
     32                  self.connection.settings.DATABASE_ENGINE,
     33                  self.connection.settings.DATABASE_NAME)
    2934
    30 connection = backend.DatabaseWrapper()
    31 DatabaseError = backend.DatabaseError
     35def connect(settings=settings):
     36    """Connect to the database specified in the given settings.
     37    """
     38    try:
     39        backend = __import__('django.db.backends.%s.base' % settings.DATABASE_ENGINE, '', '', [''])
     40    except ImportError, e:
     41        # The database backend wasn't found. Display a helpful error message
     42        # listing all possible database backends.
     43        import os
     44        backend_dir = os.path.join(__path__[0], 'backends')
     45        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')]
     46        available_backends.sort()
     47        if settings.DATABASE_ENGINE not in available_backends:
     48            raise ImproperlyConfigured, "%r isn't an available database backend. vailable options are: %s" % \
     49                (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends)))
     50        else:
     51            raise # If there's some other error, this must be an error in Django itself.
    3252
    33 # Register an event that closes the database connection
    34 # when a Django request is finished.
    35 dispatcher.connect(connection.close, signal=signals.request_finished)
    3653
     54    get_introspection_module = lambda: __import__('django.db.backends.%s.introspection' % settings.DATABASE_ENGINE, '', '', [''])
     55    get_creation_module = lambda: __import__('django.db.backends.%s.creation' % settings.DATABASE_ENGINE, '', '', [''])
     56    runshell = lambda: __import__('django.db.backends.%s.client' % settings.DATABASE_ENGINE, '', '', ['']).runshell()
     57
     58    connection = backend.DatabaseWrapper(settings)
     59    DatabaseError = backend.DatabaseError
     60
     61    return ConnectionInfo(connection, DatabaseError, backend,
     62                          get_introspection_module, get_creation_module,
     63                          runshell)
     64
     65connection_info = connect(settings)
     66
     67# backwards compatibility
     68(connection, DatabaseError, backend, get_introspection_module,
     69 get_creation_module, runshell) = (connection_info.connection,
     70                                   connection_info.DatabaseError,
     71                                   connection_info.backend,
     72                                   connection_info.get_introspection_module,
     73                                   connection_info.get_creation_module,
     74                                   connection_info.runshell)
     75
     76
     77class LazyConnectionManager(object):
     78    """Manages named connections lazily, instantiating them as
     79    they are requested.
     80    """
     81
     82    def __init__(self):
     83        self._connections = {}
     84
     85    def __getitem__(self, k):
     86        try:
     87            return self._connections[k]
     88        except KeyError:
     89            try:
     90                self.connect(k)
     91                return self._connections[k]
     92            except KeyError:
     93                raise ImproperlyConfigured, \
     94                      "No database connection '%s' has been configured" % k
     95           
     96    def connect(self, name):
     97        from django.conf import settings
     98        try:
     99            database = settings.DATABASES[name]
     100            try:
     101                database.DATABASE_ENGINE
     102            except AttributeError:
     103                # assume its a dict and convert to settings instance
     104                holder = UserSettingsHolder(settings)
     105                for k, v in database.items():
     106                    setattr(holder, k, v)
     107                    database = holder
     108                settings.DATABASES[name] = database
     109            self._connections[name] = connect(database)
     110        except AttributeError:
     111            # no named connections to set up
     112            pass
     113
     114connections = LazyConnectionManager()
     115
    37116# Register an event that resets connection.queries
    38117# when a Django request is started.
    39 def reset_queries():
     118def reset_queries(connection=connection):
    40119    connection.queries = []
    41120dispatcher.connect(reset_queries, signal=signals.request_started)
    42121
     
    46125    from django.db import transaction
    47126    transaction.rollback_unless_managed()
    48127dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception)
     128
     129# Register an event that closes the database connection
     130# when a Django request is finished.
     131dispatcher.connect(connection.close, signal=signals.request_finished)
     132
  • django/db/backends/postgresql/base.py

    === django/db/backends/postgresql/base.py
    ==================================================================
     
    2121    from django.utils._threading_local import local
    2222
    2323class DatabaseWrapper(local):
    24     def __init__(self):
     24    def __init__(self, settings):
     25        self.settings = settings
    2526        self.connection = None
    2627        self.queries = []
    2728
    2829    def cursor(self):
    29         from django.conf import settings
     30        settings = self.settings
    3031        if self.connection is None:
    3132            if settings.DATABASE_NAME == '':
    3233                from django.core.exceptions import ImproperlyConfigured
  • django/db/backends/postgresql/creation.py

    === django/db/backends/postgresql/creation.py
    ==================================================================
     
     1from django.db.backends.ansi.creation import SchemaBuilder
     2
    13# This dictionary maps Field objects to their associated PostgreSQL column
    24# types, as strings. Column-type strings can contain format strings; they'll
    35# be interpolated against the values of Field.__dict__ before being output.
     
    2830    'URLField':          'varchar(200)',
    2931    'USStateField':      'varchar(2)',
    3032}
     33
     34_builder = SchemaBuilder()
     35get_create_table = _builder.get_create_table
     36get_create_indexes = _builder.get_create_indexes
     37get_initialdata = _builder.get_initialdata
  • django/db/backends/sqlite3/base.py

    === django/db/backends/sqlite3/base.py
    ==================================================================
     
    3434    from django.utils._threading_local import local
    3535
    3636class DatabaseWrapper(local):
    37     def __init__(self):
     37    def __init__(self, settings):
     38        self.settings = settings
    3839        self.connection = None
    3940        self.queries = []
    4041
    4142    def cursor(self):
    42         from django.conf import settings
     43        settings = self.settings
    4344        if self.connection is None:
    4445            self.connection = Database.connect(settings.DATABASE_NAME,
    4546                detect_types=Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES)
  • django/db/backends/sqlite3/creation.py

    === django/db/backends/sqlite3/creation.py
    ==================================================================
     
     1from django.db.backends.ansi.creation import SchemaBuilder
     2
    13# SQLite doesn't actually support most of these types, but it "does the right
    24# thing" given more verbose field definitions, so leave them as is so that
    35# schema inspection is more useful.
     
    2729    'URLField':                     'varchar(200)',
    2830    'USStateField':                 'varchar(2)',
    2931}
     32
     33_builder = SchemaBuilder()
     34get_create_table = _builder.get_create_table
     35get_create_indexes = _builder.get_create_indexes
     36get_initialdata = _builder.get_initialdata
  • django/db/backends/ansi/__init__.py

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

    === django/db/backends/ansi/creation.py
    ==================================================================
     
     1"""ANSISQL schema manipulation functions and classes
     2"""
     3from django.db import models
     4
     5# FIXME correct handling of styles,
     6# allow style object to be passed in
     7class dummy:
     8    def __getattr__(self, attr):
     9        return lambda x: x
     10
     11class BoundStatement(object):   
     12    def __init__(self, sql, connection):
     13        self.sql = sql
     14        self.connection = connection
     15
     16    def execute(self):
     17        cursor = self.connection.cursor()
     18        cursor.execute(self.sql)
     19
     20    def __repr__(self):
     21        return "BoundStatement(%r)" % self.sql
     22
     23    def __str__(self):
     24        return self.sql
     25
     26    def __eq__(self, other):
     27        return self.sql == other.sql and self.connection == other.connection
     28
     29class SchemaBuilder(object):
     30    def __init__(self):
     31        self.models_already_seen = []
     32       
     33    def get_create_table(self, model, style=dummy()):
     34        if model in self.models_already_seen:
     35            return (None, None, None)
     36        self.models_already_seen.append(model)
     37       
     38        opts = model._meta
     39        info = opts.connection_info
     40        backend = info.backend
     41        quote_name = backend.quote_name
     42        data_types = info.get_creation_module().DATA_TYPES
     43        table_output = []
     44        pending_references = {}
     45        pending = [] # actual pending statements to execute
     46        for f in opts.fields:
     47            if isinstance(f, models.ForeignKey):
     48                rel_field = f.rel.get_related_field()
     49                data_type = self.get_rel_data_type(rel_field)
     50            else:
     51                rel_field = f
     52                data_type = f.get_internal_type()
     53            col_type = data_types[data_type]
     54            if col_type is not None:
     55                # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
     56                field_output = [style.SQL_FIELD(quote_name(f.column)),
     57                    style.SQL_COLTYPE(col_type % rel_field.__dict__)]
     58                field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
     59                if f.unique:
     60                    field_output.append(style.SQL_KEYWORD('UNIQUE'))
     61                if f.primary_key:
     62                    field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
     63                if f.rel:
     64                    if f.rel.to in self.models_already_seen:
     65                        field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
     66                            style.SQL_TABLE(quote_name(f.rel.to._meta.db_table)) + ' (' + \
     67                            style.SQL_FIELD(quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')'
     68                        )
     69                    else:
     70                        # We haven't yet created the table to which this field
     71                        # is related, so save it for later.
     72                        pr = pending_references.setdefault(f.rel.to, []).append(f)
     73                table_output.append(' '.join(field_output))
     74        if opts.order_with_respect_to:
     75            table_output.append(style.SQL_FIELD(quote_name('_order')) + ' ' + \
     76                style.SQL_COLTYPE(data_types['IntegerField']) + ' ' + \
     77                style.SQL_KEYWORD('NULL'))
     78        for field_constraints in opts.unique_together:
     79            table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
     80                ", ".join([quote_name(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
     81
     82        full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(quote_name(opts.db_table)) + ' (']
     83        for i, line in enumerate(table_output): # Combine and add commas.
     84            full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
     85        full_statement.append(');')
     86
     87        create = [BoundStatement('\n'.join(full_statement), opts.connection)]
     88
     89        if (pending_references and
     90            backend.supports_constraints):
     91            for rel_class, cols in pending_references.items():
     92                for f in cols:
     93                    rel_opts = rel_class._meta
     94                    r_table = rel_opts.db_table
     95                    r_col = f.column
     96                    table = opts.db_table
     97                    col = opts.get_field(f.rel.field_name).column
     98                    sql = style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \
     99                        (quote_name(table),
     100                        quote_name('%s_referencing_%s_%s' % (r_col, r_table, col)),
     101                        quote_name(r_col), quote_name(r_table), quote_name(col))
     102                    pending.append(BoundStatement(sql, opts.connection))
     103        return (create, pending)   
     104
     105    def get_create_indexes(self, model, style=dummy()):
     106        return [] # FIXME
     107
     108    def get_initialdata(self, model, style=dummy()):
     109        return [] # FIXME
     110
     111    def get_rel_data_type(self, f):
     112        return (f.get_internal_type() in ('AutoField', 'PositiveIntegerField',
     113                                          'PositiveSmallIntegerField')) \
     114                                          and 'IntegerField' \
     115                                          or f.get_internal_type()
  • 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"""
     2N. Using multiple database connections
     3
     4Django normally uses only a single database connection. However, support is
     5available for connecting to any number of different, named databases on a
     6per-model-class level.
     7
     8Please note that this test uses hard-coded databases, and will fail
     9unless sqlite3 is install and /tmp is writeable. It also will
     10currently fail unless the two temp databases are removed by hand
     11between runs. It also side-effects the settings as set in the
     12DJANGO_SETTINGS_MODULE. All of these are undesirable, and mean that
     13this test is almost certainly going to have to move to othertests.
     14
     15It would be really nice if the testrunner supported setup and teardown.
     16
     17"""
     18
     19# models can define which connections they will use
     20from django.db import models
     21
     22class Artist(models.Model):
     23    name = models.CharField(maxlength=100)
     24    alive = models.BooleanField(default=True)
     25
     26    def __str__(self):
     27        return self.name
     28
     29    class Meta:
     30        db_connection = 'a'
     31       
     32class Widget(models.Model):
     33    code = models.CharField(maxlength=10, unique=True)
     34    weight = models.IntegerField()
     35
     36    def __str__(self):
     37        return self.code
     38   
     39    class Meta:
     40        db_connection = 'b'
     41
     42
     43# but they don't have to
     44class Vehicle(models.Model):
     45    make = models.CharField(maxlength=20)
     46    model = models.CharField(maxlength=20)
     47    year = models.IntegerField()
     48
     49    def __str__(self):
     50        return "%d %s %s" % (self.year, self.make, self.model)
     51
     52API_TESTS = """
     53
     54# Connections are established lazily, when requested by name.
     55
     56>>> from django.conf import settings
     57>>> settings.DATABASES = {
     58...     'a': { 'DATABASE_ENGINE': 'sqlite3',
     59...            'DATABASE_NAME': '/tmp/dba.db'
     60...     },
     61...     'b': { 'DATABASE_ENGINE': 'sqlite3',
     62...            'DATABASE_NAME': '/tmp/dbb.db'
     63...     }}
     64>>> from django.db import connections
     65
     66# connections[database] holds a tuple of connection, DatabaseError, backend,
     67# get_introspection_module, get_creation_module, and runshell
     68
     69>>> connections['a']
     70Connection: <django.db.backends.sqlite3.base.DatabaseWrapper object at ...> (ENGINE=sqlite3 NAME=/tmp/dba.db)
     71>>> connections['b']
     72Connection: <django.db.backends.sqlite3.base.DatabaseWrapper object at ...> (ENGINE=sqlite3 NAME=/tmp/dbb.db)
     73
     74# Invalid connection names raise ImproperlyConfigured
     75
     76>>> connections['bad']
     77Traceback (most recent call last):
     78    ...
     79ImproperlyConfigured: No database connection 'bad' has been configured
     80
     81# For the time being, we have to install the models by hand
     82
     83>>> from django.core import management
     84>>> artist_sql = ''.join(management._get_sql_model_create(Artist)[0])
     85>>> cursor = Artist._meta.connection.cursor()
     86>>> cursor.execute(artist_sql)
     87>>> widget_sql = ''.join(management._get_sql_model_create(Widget)[0])
     88>>> cursor = Widget._meta.connection.cursor()
     89>>> cursor.execute(widget_sql)
     90
     91# Then we can play with them
     92
     93>>> a = Artist(name="Paul Klee", alive=False)
     94>>> a.save()
     95>>> a._meta.connection.settings.DATABASE_NAME
     96'/tmp/dba.db'
     97>>> w = Widget(code='100x2r', weight=1000)
     98>>> w.save()
     99>>> w._meta.connection.settings.DATABASE_NAME
     100'/tmp/dbb.db'
     101>>> v = Vehicle(make='Chevy', model='Camaro', year='1966')
     102>>> v.save()
     103>>> v._meta.connection.settings.DATABASE_NAME
     104':memory:'
     105
     106# Managers use their models' connections
     107
     108>>> artists = Artist.objects.all()
     109>>> list(artists)
     110[<Artist: Paul Klee>]
     111>>> artists[0]._meta.connection.settings.DATABASE_NAME
     112'/tmp/dba.db'
     113>>> widgets = Widget.objects.all()
     114>>> list(widgets)
     115[<Widget: 100x2r>]
     116>>> widgets[0]._meta.connection.settings.DATABASE_NAME
     117'/tmp/dbb.db'
     118>>> vehicles = Vehicle.objects.all()
     119>>> list(vehicles)
     120[<Vehicle: 1966 Chevy Camaro>]
     121>>> vehicles[0]._meta.connection.settings.DATABASE_NAME
     122':memory:'
     123
     124# Managed transactions may be restricted to certain databases
     125
     126# But by default they cover all databases
     127
     128
     129"""
  • tests/modeltests/manager_schema_manipulation/__init__.py

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

    === tests/modeltests/manager_schema_manipulation/models.py
    ==================================================================
     
     1"""
     2N. Schema manipulations
     3
     4Django uses a model's manager to perform schema manipulations such as
     5creating or dropping the model's table.
     6
     7Please note that your settings file must define DATABASES with names
     8'a' and 'b' for this test.
     9"""
     10
     11from django.db import models
     12
     13# default connection
     14class DA(models.Model):
     15    name = models.CharField(maxlength=20)
     16
     17    def __str__(self):
     18        return self.name
     19   
     20# connection a
     21class AA(models.Model):
     22    name = models.CharField(maxlength=20)
     23    # This creates a cycle in the dependency graph
     24    c = models.ForeignKey('AC', null=True)
     25   
     26    def __str__(self):
     27        return self.name
     28
     29    class Meta:
     30        db_connection = 'a'
     31
     32class AB(models.Model):
     33    name = models.CharField(maxlength=20)
     34    a = models.ForeignKey(AA)
     35
     36    def __str__(self):
     37        return self.name
     38
     39    class Meta:
     40        db_connection = 'a'
     41
     42class AC(models.Model):
     43    name = models.CharField(maxlength=20)
     44    b = models.ForeignKey(AB)
     45
     46    def __str__(self):
     47        return self.name
     48
     49    class Meta:
     50        db_connection = 'a'
     51
     52# connection b
     53class BA(models.Model):
     54    name = models.CharField(maxlength=20)
     55
     56    def __str__(self):
     57        return self.name
     58
     59    class Meta:
     60        db_connection = 'b'
     61
     62class BB(models.Model):
     63    name = models.CharField(maxlength=20)
     64    a = models.ForeignKey(BA)
     65   
     66    def __str__(self):
     67        return self.name
     68
     69    class Meta:
     70        db_connection = 'b'
     71
     72
     73
     74API_TESTS = """
     75
     76# models can use the default connection or a named connection
     77
     78# FIXME: DA is already installed
     79# models can be installed individually
     80
     81>>> BA._default_manager.install()
     82(<class 'modeltests.manager_schema_manipulation.models.BA'>, [BoundStatement('CREATE TABLE "manager_schema_manipulation_ba" (...);')], [])
     83>>> BB._default_manager.install()
     84(<class 'modeltests.manager_schema_manipulation.models.BB'>, [BoundStatement('CREATE TABLE "manager_schema_manipulation_bb" (...);')], [])
     85>>> list(BA.objects.all())
     86[]
     87>>> BA(name="something").save()
     88>>> BA.objects.all()
     89[<BA: something>]
     90
     91# models with un-installable dependencies will return a list of
     92# pending statements; these are bound to the model's connection and should
     93# be executed after all other models have been created
     94
     95>>> result = AA._default_manager.install()
     96>>> result
     97(<class 'modeltests.manager_schema_manipulation.models.AA'>, [BoundStatement('CREATE TABLE "manager_schema_manipulation_aa" (...);')], [BoundStatement('ALTER TABLE "manager_schema_manipulation_aa" ADD CONSTRAINT "c_id_referencing_manager_schema_manipulation_ac_id" FOREIGN KEY ("c_id") REFERENCES "manager_schema_manipulation_ac" ("id");')])
     98
     99
     100"""
Back to Top