Django

Code

MultipleDatabaseSupport: p4.diff

File p4.diff, 36.2 kB (added by jpellerin@gmail.com, 2 years ago)

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

  • django/db/models/base.py

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
     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

    old new  
    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

    old new  
     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

    old new  
  • django/db/backends/ansi/creation.py

    old new  
     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

    old new  
  • tests/modeltests/multiple_databases/models.py

    old new  
     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

    old new  
  • tests/modeltests/manager_schema_manipulation/models.py

    old new  
     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"""