MultipleDatabaseSupport: p5.diff
File p5.diff, 52.8 KB (added by , 18 years ago) |
---|
-
django/db/models/base.py
=== django/db/models/base.py ==================================================================
7 7 from django.db.models.related import RelatedObject 8 8 from django.db.models.query import orderlist2sql, delete_objects 9 9 from django.db.models.options import Options, AdminOptions 10 from django.db import connection, backend,transaction10 from django.db import transaction 11 11 from django.db.models import signals 12 12 from django.db.models.loading import register_models 13 13 from django.dispatch import dispatcher … … 38 38 new_class._meta.parents.extend(base._meta.parents) 39 39 40 40 model_module = sys.modules[new_class.__module__] 41 41 42 42 if getattr(new_class._meta, 'app_label', None) is None: 43 43 # Figure out the app_label by looking one level up. 44 44 # For 'django.contrib.sites.models', this would be 'sites'. … … 154 154 def save(self): 155 155 dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self) 156 156 157 info = self._meta.connection_info 158 connection = info.connection 159 backend = info.backend 157 160 non_pks = [f for f in self._meta.fields if not f.primary_key] 158 161 cursor = connection.cursor() 159 162 … … 201 204 backend.get_pk_default_value())) 202 205 if self._meta.has_auto_field and not pk_set: 203 206 setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column)) 204 transaction.commit_unless_managed( )207 transaction.commit_unless_managed([connection]) 205 208 206 209 # Run any post-save hooks. 207 210 dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self) … … 272 275 return dict(field.choices).get(value, value) 273 276 274 277 def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs): 278 backend = self._meta.connection_info.backend 275 279 op = is_next and '>' or '<' 276 280 where = '(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \ 277 281 (backend.quote_name(field.column), op, backend.quote_name(field.column), … … 286 290 raise self.DoesNotExist, "%s matching query does not exist." % self.__class__._meta.object_name 287 291 288 292 def _get_next_or_previous_in_order(self, is_next): 293 backend = self._meta.connection_info.backend 289 294 cachename = "__%s_order_cache" % is_next 290 295 if not hasattr(self, cachename): 291 296 op = is_next and '>' or '<' … … 374 379 rel = rel_field.rel.to 375 380 m2m_table = rel_field.m2m_db_table() 376 381 this_id = self._get_pk_val() 382 info = self._meta.connection_info 383 connection = info.connection 384 backend = info.backend 377 385 cursor = connection.cursor() 378 386 cursor.execute("DELETE FROM %s WHERE %s = %%s" % \ 379 387 (backend.quote_name(m2m_table), … … 383 391 backend.quote_name(rel_field.m2m_column_name()), 384 392 backend.quote_name(rel_field.m2m_reverse_name())) 385 393 cursor.executemany(sql, [(this_id, i) for i in id_list]) 386 transaction.commit_unless_managed( )394 transaction.commit_unless_managed([connection]) 387 395 388 396 ############################################ 389 397 # HELPER FUNCTIONS (CURRIED MODEL METHODS) # … … 392 400 # ORDERING METHODS ######################### 393 401 394 402 def method_set_order(ordered_obj, self, id_list): 403 connection_info = ordered_obj.connection_info 404 connection = info.connection 405 backend = info.backend 406 395 407 cursor = connection.cursor() 396 408 # Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s" 397 409 sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \ … … 400 412 backend.quote_name(ordered_obj.pk.column)) 401 413 rel_val = getattr(self, ordered_obj.order_with_respect_to.rel.field_name) 402 414 cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)]) 403 transaction.commit_unless_managed( )415 transaction.commit_unless_managed([connection]) 404 416 405 417 def method_get_order(ordered_obj, self): 418 connection_info = ordered_obj.connection_info 419 connection = info.connection 420 backend = info.backend 406 421 cursor = connection.cursor() 407 422 # Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order" 408 423 sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \ -
django/db/models/manager.py
=== django/db/models/manager.py ==================================================================
99 99 def values(self, *args, **kwargs): 100 100 return self.get_query_set().values(*args, **kwargs) 101 101 102 ####################### 103 # SCHEMA MANIPULATION # 104 ####################### 105 106 def install(self, initial_data=False): 107 """Install my model's table, indexes and (if requested) initial data. 108 109 Returns a 2-tuple of the lists of statements executed and 110 statements pending. Pending statements are those that could 111 not yet be executed, such as foreign key constraints for 112 tables that don't exist at install time. 113 """ 114 creator = self.model._meta.connection_info.get_creation_module() 115 run, pending = creator.get_create_table(self.model) 116 run += creator.get_create_indexes(self.model) 117 pending += creator.get_create_many_to_many(self.model) 118 if initial_data: 119 run += creator.get_initialdata(self.model) 120 121 executed = [] 122 for statement in run: 123 statement.execute() 124 executed.append(statement) 125 return (executed, pending) 126 127 def load_initial_data(self): 128 """Load initial data for my model into the database.""" 129 pass 130 131 def drop(self): 132 """Drop my model's table.""" 133 pass 134 135 # Future... 136 137 def add_column(self, column): 138 """Add a column to my model's table""" 139 pass 140 141 def drop_column(self, column): 142 """Drop a column from my model's table""" 143 pass 144 145 102 146 class ManagerDescriptor(object): 103 147 # This class ensures managers aren't accessible via model instances. 104 148 # For example, Poll.objects works, but poll_obj.objects raises AttributeError. -
django/db/models/options.py
=== django/db/models/options.py ==================================================================
1 1 from django.conf import settings 2 from django.db import connection_info, connections 2 3 from django.db.models.related import RelatedObject 3 4 from django.db.models.fields.related import ManyToManyRel 4 5 from django.db.models.fields import AutoField, FieldDoesNotExist … … 11 12 # Calculate the verbose_name by converting from InitialCaps to "lowercase with spaces". 12 13 get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip() 13 14 14 DEFAULT_NAMES = ('verbose_name', 'db_ table', 'ordering',15 DEFAULT_NAMES = ('verbose_name', 'db_connection', 'db_table', 'ordering', 15 16 'unique_together', 'permissions', 'get_latest_by', 16 17 'order_with_respect_to', 'app_label') 17 18 … … 20 21 self.fields, self.many_to_many = [], [] 21 22 self.module_name, self.verbose_name = None, None 22 23 self.verbose_name_plural = None 24 self.db_connection = None 23 25 self.db_table = '' 24 26 self.ordering = [] 25 27 self.unique_together = [] … … 56 58 raise TypeError, "'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys()) 57 59 else: 58 60 self.verbose_name_plural = self.verbose_name + 's' 61 # 59 62 del self.meta 60 63 61 64 def _prepare(self, model): … … 88 91 def __repr__(self): 89 92 return '<Options for %s>' % self.object_name 90 93 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 91 105 def get_field(self, name, many_to_many=True): 92 106 "Returns the requested field by name. Raises FieldDoesNotExist on error." 93 107 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 ==================================================================
8 8 _app_list = None # Cache of installed apps. 9 9 _app_models = {} # Dictionary of models against app label 10 10 # 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 12 14 def get_apps(): 13 15 "Returns a list of all installed modules that contain models." 14 16 global _app_list … … 35 37 return __import__(app_name, '', '', ['models']).models 36 38 raise ImproperlyConfigured, "App with label %s could not be found" % app_label 37 39 38 def get_models(app_mod=None ):40 def get_models(app_mod=None, creation_order=False): 39 41 """ 40 42 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. 42 46 """ 43 47 app_list = get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish. 44 48 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() 46 55 else: 47 56 model_list = [] 48 57 for app_mod in app_list: … … 75 84 model_name = model._meta.object_name.lower() 76 85 model_dict = _app_models.setdefault(app_label, {}) 77 86 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, transaction1 from django.db import backend, connection, connections, transaction 2 2 from django.db.models.fields import DateField, FieldDoesNotExist 3 3 from django.db.models import signals 4 4 from django.dispatch import dispatcher … … 158 158 # undefined, so we convert it to a list of tuples. 159 159 extra_select = self._select.items() 160 160 161 cursor = connection.cursor()161 cursor = self.model._meta.connection.cursor() 162 162 select, sql, params = self._get_sql_clause() 163 163 cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 164 164 fill_cache = self._select_related … … 178 178 179 179 def count(self): 180 180 "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 181 186 counter = self._clone() 182 187 counter._order_by = () 183 188 counter._offset = None … … 505 510 columns = [f.column for f in self.model._meta.fields] 506 511 field_names = [f.attname for f in self.model._meta.fields] 507 512 513 info = self.model._meta.connection_info 514 backend = info.backend 515 connection = info.connection 508 516 cursor = connection.cursor() 509 517 select, sql, params = self._get_sql_clause() 510 518 select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns] … … 524 532 class DateQuerySet(QuerySet): 525 533 def iterator(self): 526 534 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 527 540 self._order_by = () # Clear this because it'll mess things up otherwise. 528 541 if self._field.null: 529 542 self._where.append('%s.%s IS NOT NULL' % \ … … 616 629 where2 = ['(NOT (%s))' % " AND ".join(where)] 617 630 return tables, joins, where2, params 618 631 619 def get_where_clause(lookup_type, table_prefix, field_name, value): 632 def get_where_clause(opts, lookup_type, table_prefix, field_name, value): 633 backend = opts.connection_info.backend 634 620 635 if table_prefix.endswith('.'): 621 636 table_prefix = backend.quote_name(table_prefix[:-1])+'.' 622 637 field_name = backend.quote_name(field_name) … … 745 760 intermediate_table = None 746 761 join_required = False 747 762 763 info = current_opts.connection_info 764 backend = info.backend 765 connection = info.connection 766 748 767 name = path.pop(0) 749 768 # Has the primary key been requested? If so, expand it out 750 769 # to be the name of the current class' primary key … … 872 891 else: 873 892 column = field.column 874 893 875 where.append(get_where_clause(c lause, current_table + '.', column, value))894 where.append(get_where_clause(current_opts, clause, current_table + '.', column, value)) 876 895 params.extend(field.get_db_prep_lookup(clause, value)) 877 896 878 897 return tables, joins, where, params … … 882 901 ordered_classes = seen_objs.keys() 883 902 ordered_classes.reverse() 884 903 885 cursor = connection.cursor()886 904 887 905 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 888 912 seen_objs[cls] = seen_objs[cls].items() 889 913 seen_objs[cls].sort() 890 914 … … 919 943 920 944 # Now delete the actual data 921 945 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 922 952 seen_objs[cls].reverse() 923 953 pk_list = [pk for pk,instance in seen_objs[cls]] 924 954 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 1 from django.conf import settings, UserSettingsHolder 2 2 from django.core import signals 3 from django.core.exceptions import ImproperlyConfigured 3 4 from django.dispatch import dispatcher 4 5 5 6 __all__ = ('backend', 'connection', 'DatabaseError') … … 7 8 if not settings.DATABASE_ENGINE: 8 9 settings.DATABASE_ENGINE = 'dummy' 9 10 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. 11 class 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 25 28 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) 29 34 30 connection = backend.DatabaseWrapper() 31 DatabaseError = backend.DatabaseError 35 def 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. 32 52 33 # Register an event that closes the database connection34 # when a Django request is finished.35 dispatcher.connect(connection.close, signal=signals.request_finished)36 53 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 65 connection_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 77 class 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 __iter__(self): 86 return self._connections.keys() 87 88 def __getattr__(self, attr): 89 return getattr(self._connections, attr) 90 91 def __getitem__(self, k): 92 try: 93 return self._connections[k] 94 except KeyError: 95 try: 96 self.connect(k) 97 return self._connections[k] 98 except KeyError: 99 raise ImproperlyConfigured, \ 100 "No database connection '%s' has been configured" % k 101 102 def __setattr(self, attr, val): 103 setattr(self._connections, attr, val) 104 105 def connect(self, name): 106 from django.conf import settings 107 try: 108 database = settings.DATABASES[name] 109 try: 110 database.DATABASE_ENGINE 111 except AttributeError: 112 # assume its a dict and convert to settings instance 113 holder = UserSettingsHolder(settings) 114 for k, v in database.items(): 115 setattr(holder, k, v) 116 database = holder 117 settings.DATABASES[name] = database 118 self._connections[name] = connect(database) 119 except AttributeError: 120 # no named connections to set up 121 pass 122 connections = LazyConnectionManager() 123 37 124 # Register an event that resets connection.queries 38 125 # when a Django request is started. 39 def reset_queries( ):126 def reset_queries(connection=connection): 40 127 connection.queries = [] 41 128 dispatcher.connect(reset_queries, signal=signals.request_started) 42 129 … … 46 133 from django.db import transaction 47 134 transaction.rollback_unless_managed() 48 135 dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception) 136 137 # Register an event that closes the database connection 138 # when a Django request is finished. 139 dispatcher.connect(connection.close, signal=signals.request_finished) 140 -
django/db/backends/ado_mssql/creation.py
=== django/db/backends/ado_mssql/creation.py ==================================================================
1 from django.db.backends.ansi.creation import SchemaBuilder 2 1 3 DATA_TYPES = { 2 4 'AutoField': 'int IDENTITY (1, 1)', 3 5 'BooleanField': 'bit', … … 24 26 'URLField': 'varchar(200)', 25 27 'USStateField': 'varchar(2)', 26 28 } 29 30 _builder = SchemaBuilder() 31 get_create_table = _builder.get_create_table 32 get_create_indexes = _builder.get_create_indexes 33 get_create_many_to_many = _builder.get_create_many_to_many 34 get_initialdata = _builder.get_initialdata -
django/db/backends/postgresql/base.py
=== django/db/backends/postgresql/base.py ==================================================================
21 21 from django.utils._threading_local import local 22 22 23 23 class DatabaseWrapper(local): 24 def __init__(self): 24 def __init__(self, settings): 25 self.settings = settings 25 26 self.connection = None 26 27 self.queries = [] 27 28 28 29 def cursor(self): 29 from django.conf importsettings30 settings = self.settings 30 31 if self.connection is None: 31 32 if settings.DATABASE_NAME == '': 32 33 from django.core.exceptions import ImproperlyConfigured -
django/db/backends/postgresql/creation.py
=== django/db/backends/postgresql/creation.py ==================================================================
1 from django.db.backends.ansi.creation import SchemaBuilder 2 1 3 # This dictionary maps Field objects to their associated PostgreSQL column 2 4 # types, as strings. Column-type strings can contain format strings; they'll 3 5 # be interpolated against the values of Field.__dict__ before being output. … … 28 30 'URLField': 'varchar(200)', 29 31 'USStateField': 'varchar(2)', 30 32 } 33 34 _builder = SchemaBuilder() 35 get_create_table = _builder.get_create_table 36 get_create_indexes = _builder.get_create_indexes 37 get_create_many_to_many = _builder.get_create_many_to_many 38 get_initialdata = _builder.get_initialdata -
django/db/backends/sqlite3/base.py
=== django/db/backends/sqlite3/base.py ==================================================================
34 34 from django.utils._threading_local import local 35 35 36 36 class DatabaseWrapper(local): 37 def __init__(self): 37 def __init__(self, settings): 38 self.settings = settings 38 39 self.connection = None 39 40 self.queries = [] 40 41 41 42 def cursor(self): 42 from django.conf importsettings43 settings = self.settings 43 44 if self.connection is None: 44 45 self.connection = Database.connect(settings.DATABASE_NAME, 45 46 detect_types=Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES) -
django/db/backends/sqlite3/creation.py
=== django/db/backends/sqlite3/creation.py ==================================================================
1 from django.db.backends.ansi.creation import SchemaBuilder 2 1 3 # SQLite doesn't actually support most of these types, but it "does the right 2 4 # thing" given more verbose field definitions, so leave them as is so that 3 5 # schema inspection is more useful. … … 27 29 'URLField': 'varchar(200)', 28 30 'USStateField': 'varchar(2)', 29 31 } 32 33 _builder = SchemaBuilder() 34 get_create_table = _builder.get_create_table 35 get_create_indexes = _builder.get_create_indexes 36 get_create_many_to_many = _builder.get_create_many_to_many 37 get_initialdata = _builder.get_initialdata -
django/db/backends/mysql/creation.py
=== django/db/backends/mysql/creation.py ==================================================================
1 from django.db.backends.ansi.creation import SchemaBuilder 2 1 3 # This dictionary maps Field objects to their associated MySQL column 2 4 # types, as strings. Column-type strings can contain format strings; they'll 3 5 # be interpolated against the values of Field.__dict__ before being output. … … 28 30 'URLField': 'varchar(200)', 29 31 'USStateField': 'varchar(2)', 30 32 } 33 34 _builder = SchemaBuilder() 35 get_create_table = _builder.get_create_table 36 get_create_indexes = _builder.get_create_indexes 37 get_create_many_to_many = _builder.get_create_many_to_many 38 get_initialdata = _builder.get_initialdata -
django/db/backends/oracle/creation.py
=== django/db/backends/oracle/creation.py ==================================================================
1 from django.db.backends.ansi.creation import SchemaBuilder 2 1 3 DATA_TYPES = { 2 4 'AutoField': 'number(38)', 3 5 'BooleanField': 'number(1)', … … 24 26 'URLField': 'varchar(200)', 25 27 'USStateField': 'varchar(2)', 26 28 } 29 30 _builder = SchemaBuilder() 31 get_create_table = _builder.get_create_table 32 get_create_indexes = _builder.get_create_indexes 33 get_create_many_to_many = _builder.get_create_many_to_many 34 get_initialdata = _builder.get_initialdata -
django/db/backends/ansi/__init__.py
=== django/db/backends/ansi/__init__.py ==================================================================
1 pass -
django/db/backends/ansi/creation.py
=== django/db/backends/ansi/creation.py ==================================================================
1 """ANSISQL schema manipulation functions and classes 2 """ 3 from django.db import models 4 5 # FIXME correct handling of styles, 6 # allow style object to be passed in 7 class dummy: 8 def __getattr__(self, attr): 9 return lambda x: x 10 11 class BoundStatement(object): 12 """Represents an SQL statement that is to be executed, at some point in 13 the future, using a specific database connection. 14 """ 15 def __init__(self, sql, connection): 16 self.sql = sql 17 self.connection = connection 18 19 def execute(self): 20 cursor = self.connection.cursor() 21 cursor.execute(self.sql) 22 23 def __repr__(self): 24 return "BoundStatement(%r)" % self.sql 25 26 def __str__(self): 27 return self.sql 28 29 def __eq__(self, other): 30 return self.sql == other.sql and self.connection == other.connection 31 32 class SchemaBuilder(object): 33 """Basic ANSI SQL schema element builder. Instances of this class may be 34 used to construct SQL expressions that create or drop schema elements such 35 as tables, indexes and (for those backends that support them) foreign key 36 or other constraints. 37 """ 38 def __init__(self): 39 self.models_already_seen = [] 40 41 def get_create_table(self, model, style=dummy()): 42 """Construct and return the SQL expression(s) needed to create the 43 table for the given model, and any constraints on that 44 table. The return value is a 2-tuple. The first element of the tuple 45 is a list of BoundStatements that may be executed immediately. The 46 second is a list of BoundStatements representing constraints that 47 can't be executed immediately because (for instance) the referent 48 table does not exist. 49 """ 50 if model in self.models_already_seen: 51 return (None, None, None) 52 self.models_already_seen.append(model) 53 54 opts = model._meta 55 info = opts.connection_info 56 backend = info.backend 57 quote_name = backend.quote_name 58 data_types = info.get_creation_module().DATA_TYPES 59 table_output = [] 60 pending_references = {} 61 pending = [] # actual pending statements to execute 62 for f in opts.fields: 63 if isinstance(f, models.ForeignKey): 64 rel_field = f.rel.get_related_field() 65 data_type = self.get_rel_data_type(rel_field) 66 else: 67 rel_field = f 68 data_type = f.get_internal_type() 69 col_type = data_types[data_type] 70 if col_type is not None: 71 # Make the definition (e.g. 'foo VARCHAR(30)') for this field. 72 field_output = [style.SQL_FIELD(quote_name(f.column)), 73 style.SQL_COLTYPE(col_type % rel_field.__dict__)] 74 field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or ''))) 75 if f.unique: 76 field_output.append(style.SQL_KEYWORD('UNIQUE')) 77 if f.primary_key: 78 field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 79 if f.rel: 80 if f.rel.to in self.models_already_seen: 81 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \ 82 style.SQL_TABLE(quote_name(f.rel.to._meta.db_table)) + ' (' + \ 83 style.SQL_FIELD(quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' 84 ) 85 else: 86 # We haven't yet created the table to which this field 87 # is related, so save it for later. 88 pr = pending_references.setdefault(f.rel.to, []).append(f) 89 table_output.append(' '.join(field_output)) 90 if opts.order_with_respect_to: 91 table_output.append(style.SQL_FIELD(quote_name('_order')) + ' ' + \ 92 style.SQL_COLTYPE(data_types['IntegerField']) + ' ' + \ 93 style.SQL_KEYWORD('NULL')) 94 for field_constraints in opts.unique_together: 95 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ 96 ", ".join([quote_name(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints])) 97 98 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(quote_name(opts.db_table)) + ' ('] 99 for i, line in enumerate(table_output): # Combine and add commas. 100 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 101 full_statement.append(');') 102 103 create = [BoundStatement('\n'.join(full_statement), opts.connection)] 104 105 if (pending_references and 106 backend.supports_constraints): 107 for rel_class, cols in pending_references.items(): 108 for f in cols: 109 rel_opts = rel_class._meta 110 r_table = rel_opts.db_table 111 r_col = f.column 112 table = opts.db_table 113 col = opts.get_field(f.rel.field_name).column 114 sql = style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ 115 (quote_name(table), 116 quote_name('%s_referencing_%s_%s' % (r_col, r_table, col)), 117 quote_name(r_col), quote_name(r_table), quote_name(col)) 118 pending.append(BoundStatement(sql, opts.connection)) 119 return (create, pending) 120 121 def get_create_indexes(self, model, style=dummy()): 122 """Construct and return SQL statements needed to create the indexes for 123 a model. Returns a list of BoundStatements. 124 """ 125 info = model._meta.connection_info 126 backend = info.backend 127 connection = info.connection 128 output = [] 129 for f in model._meta.fields: 130 if f.db_index: 131 unique = f.unique and 'UNIQUE ' or '' 132 output.append( 133 BoundStatement( 134 ' '.join( 135 [style.SQL_KEYWORD('CREATE %sINDEX' % unique), 136 style.SQL_TABLE('%s_%s' % 137 (model._meta.db_table, f.column)), 138 style.SQL_KEYWORD('ON'), 139 style.SQL_TABLE( 140 backend.quote_name(model._meta.db_table)), 141 "(%s);" % style.SQL_FIELD( 142 backend.quote_name(f.column))]), 143 connection) 144 ) 145 return output 146 147 def get_create_many_to_many(self, model, style=dummy()): 148 """Construct and return SQL statements needed to create the 149 tables and relationships for all many-to-many relations 150 defined in the model. Returns a list of bound statments. Note 151 that these statements should only be execute after all models 152 for an app have been created. 153 """ 154 info = model._meta.connection_info 155 backend = info.backend 156 connection = info.connection 157 data_types = info.get_creation_module().DATA_TYPES 158 opts = model._meta 159 output = [] 160 for f in opts.many_to_many: 161 if not isinstance(f.rel, models.GenericRel): 162 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ 163 style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' ('] 164 table_output.append(' %s %s %s,' % \ 165 (style.SQL_FIELD(backend.quote_name('id')), 166 style.SQL_COLTYPE(data_types['AutoField']), 167 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'))) 168 table_output.append(' %s %s %s %s (%s),' % \ 169 (style.SQL_FIELD(backend.quote_name(f.m2m_column_name())), 170 style.SQL_COLTYPE(data_types[self.get_rel_data_type(opts.pk)] % opts.pk.__dict__), 171 style.SQL_KEYWORD('NOT NULL REFERENCES'), 172 style.SQL_TABLE(backend.quote_name(opts.db_table)), 173 style.SQL_FIELD(backend.quote_name(opts.pk.column)))) 174 table_output.append(' %s %s %s %s (%s),' % \ 175 (style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())), 176 style.SQL_COLTYPE(data_types[self.get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__), 177 style.SQL_KEYWORD('NOT NULL REFERENCES'), 178 style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)), 179 style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)))) 180 table_output.append(' %s (%s, %s)' % \ 181 (style.SQL_KEYWORD('UNIQUE'), 182 style.SQL_FIELD(backend.quote_name(f.m2m_column_name())), 183 style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())))) 184 table_output.append(');') 185 output.append(BoundStatement('\n'.join(table_output), 186 connection)) 187 return output 188 189 190 def get_initialdata(self, model, style=dummy()): 191 return [] # FIXME 192 193 def get_rel_data_type(self, f): 194 return (f.get_internal_type() in ('AutoField', 'PositiveIntegerField', 195 'PositiveSmallIntegerField')) \ 196 and 'IntegerField' \ 197 or f.get_internal_type() -
django/db/transaction.py
=== django/db/transaction.py ==================================================================
16 16 import thread 17 17 except ImportError: 18 18 import dummy_thread as thread 19 from django .db import connection19 from django import db 20 20 from django.conf import settings 21 21 22 22 class TransactionManagementError(Exception): … … 116 116 Puts the transaction manager into a manual state: managed transactions have 117 117 to be committed explicitly by the user. If you switch off transaction 118 118 management and there is a pending commit/rollback, the data will be 119 commited. 119 commited. Note that managed state applies across all connections. 120 120 """ 121 121 thread_ident = thread.get_ident() 122 122 top = state.get(thread_ident, None) 123 123 if top: 124 124 top[-1] = flag 125 125 if not flag and is_dirty(): 126 connection._commit() 126 for cx in all_connections(): 127 cx._commit() 127 128 set_clean() 128 129 else: 129 130 raise TransactionManagementError("This code isn't under transaction management") 130 131 131 def commit_unless_managed( ):132 def commit_unless_managed(connections=None): 132 133 """ 133 134 Commits changes if the system is not in managed transaction mode. 134 135 """ 135 136 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() 137 143 else: 138 144 set_dirty() 139 145 140 def rollback_unless_managed( ):146 def rollback_unless_managed(connections=None): 141 147 """ 142 148 Rolls back changes if the system is not in managed transaction mode. 143 149 """ 144 150 if not is_managed(): 145 connection._rollback() 151 if connections is None: 152 connections = all_connections() 153 for cx in connections: 154 cx._rollback() 146 155 else: 147 156 set_dirty() 148 157 149 def commit( ):158 def commit(connections=None): 150 159 """ 151 160 Does the commit itself and resets the dirty flag. 152 161 """ 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() 154 168 set_clean() 155 169 156 def rollback( ):170 def rollback(connections=None): 157 171 """ 158 172 This function does the rollback itself and resets the dirty flag. 159 173 """ 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() 161 180 set_clean() 162 181 163 182 ############## … … 179 198 leave_transaction_management() 180 199 return _autocommit 181 200 182 def commit_on_success(func ):201 def commit_on_success(func, connections=None): 183 202 """ 184 203 This decorator activates commit on response. This way, if the view function 185 204 runs successfully, a commit is made; if the viewfunc produces an exception, … … 198 217 raise 199 218 else: 200 219 if is_dirty(): 201 commit( )220 commit(connections) 202 221 return res 203 222 finally: 204 223 leave_transaction_management() … … 220 239 leave_transaction_management() 221 240 222 241 return _commit_manually 242 243 ########### 244 # HELPERS # 245 ########### 246 247 def all_connections(): 248 return [db.connection] + [ c.connection 249 for c in db.connections.values() ] 250 251 def 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 -
tests/modeltests/multiple_databases/__init__.py
=== tests/modeltests/multiple_databases/__init__.py ==================================================================
1 pass -
tests/modeltests/multiple_databases/models.py
=== tests/modeltests/multiple_databases/models.py ==================================================================
1 """ 2 N. Using multiple database connections 3 4 Django normally uses only a single database connection. However, support is 5 available for connecting to any number of different, named databases on a 6 per-model-class level. 7 8 Please note that this test uses hard-coded databases, and will fail 9 unless sqlite3 is install and /tmp is writeable. It also will 10 currently fail unless the two temp databases are removed by hand 11 between runs. It also side-effects the settings as set in the 12 DJANGO_SETTINGS_MODULE. All of these are undesirable, and mean that 13 this test is almost certainly going to have to move to othertests. 14 15 It would be really nice if the testrunner supported setup and teardown. 16 17 """ 18 19 # models can define which connections they will use 20 from django.db import models 21 22 class 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 32 class 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 44 class 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 52 API_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'] 70 Connection: <django.db.backends.sqlite3.base.DatabaseWrapper object at ...> (ENGINE=sqlite3 NAME=/tmp/dba.db) 71 >>> connections['b'] 72 Connection: <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'] 77 Traceback (most recent call last): 78 ... 79 ImproperlyConfigured: 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 # When not using transaction management, model save will commit only 125 # for the model's connection 126 127 >>> from django.db import transaction 128 >>> transaction.enter_transaction_management() 129 >>> a = Artist(name="Joan Miro", alive=False) 130 >>> w = Widget(code="99rbln", weight=1) 131 >>> a.save() 132 133 # only connection 'a' is committed, so if we rollback all connections 134 # we'll forget the new Widget. 135 136 >>> transaction.rollback() 137 >>> list(Artist.objects.all()) 138 [<Artist: Paul Klee>, <Artist: Joan Miro>] 139 >>> list(Widget.objects.all()) 140 [<Widget: 100x2r>] 141 142 # Managed transaction state applies across all connections. 143 144 >>> transaction.managed(True) 145 146 # When managed, just as when using a single connection, updates are 147 # not committed until a commit is issued. 148 149 >>> a = Artist(name="Pablo Picasso", alive=False) 150 >>> a.save() 151 >>> w = Widget(code="99rbln", weight=1) 152 >>> w.save() 153 >>> v = Vehicle(make='Pontiac', model='Fiero', year='1987') 154 >>> v.save() 155 156 # The connections argument may be passed to commit, rollback, and the 157 # commit_on_success decorator as a keyword argument, or the first (for commit 158 # and rollback) or second (for the decorator) positional argument. It 159 # may be passed as a single connection info object, a single 160 # connection object, a single connection name, or a list of connection 161 # info objects, connection objects, or connection names. 162 163 >>> transaction.commit(connections['b']) 164 >>> transaction.commit('b') 165 >>> transaction.commit(['a', 'b']) 166 >>> transaction.commit(connections) 167 168 # When omitted entirely, the transaction command applies to all 169 # connections. Here we have committed connections 'a' and 'b', but not 170 # the default connection, so the new vehicle is lost on rollback. 171 172 >>> transaction.rollback() 173 >>> list(Artist.objects.all()) 174 [<Artist: Paul Klee>, <Artist: Joan Miro>, <Artist: Pablo Picasso>] 175 >>> list(Widget.objects.all()) 176 [<Widget: 100x2r>, <Widget: 99rbln>] 177 >>> list(Vehicle.objects.all()) 178 [<Vehicle: 1966 Chevy Camaro>] 179 180 >>> transaction.leave_transaction_management() 181 182 """ -
tests/modeltests/manager_schema_manipulation/__init__.py
=== tests/modeltests/manager_schema_manipulation/__init__.py ==================================================================
1 pass -
tests/modeltests/manager_schema_manipulation/models.py
=== tests/modeltests/manager_schema_manipulation/models.py ==================================================================
1 """ 2 N. Schema manipulations 3 4 Django uses a model's manager to perform schema manipulations such as 5 creating or dropping the model's table. 6 7 Please note that your settings file must define DATABASES with names 8 'p' and 'q' for this test. 9 """ 10 11 from django.db import models 12 13 # default connection 14 class DA(models.Model): 15 name = models.CharField(maxlength=20) 16 17 def __str__(self): 18 return self.name 19 20 # connection p 21 class PA(models.Model): 22 name = models.CharField(maxlength=20) 23 # This creates a cycle in the dependency graph 24 c = models.ForeignKey('PC', null=True) 25 26 def __str__(self): 27 return self.name 28 29 class Meta: 30 db_connection = 'p' 31 32 class PB(models.Model): 33 name = models.CharField(maxlength=20) 34 a = models.ForeignKey(PA) 35 36 def __str__(self): 37 return self.name 38 39 class Meta: 40 db_connection = 'p' 41 42 class PC(models.Model): 43 name = models.CharField(maxlength=20) 44 b = models.ForeignKey(PB) 45 46 def __str__(self): 47 return self.name 48 49 class Meta: 50 db_connection = 'p' 51 52 # connection q 53 class QA(models.Model): 54 name = models.CharField(maxlength=20) 55 56 def __str__(self): 57 return self.name 58 59 class Meta: 60 db_connection = 'q' 61 62 class QB(models.Model): 63 name = models.CharField(maxlength=20) 64 a = models.ForeignKey(QA) 65 66 def __str__(self): 67 return self.name 68 69 class Meta: 70 db_connection = 'q' 71 72 # many-many 73 class QC(models.Model): 74 name = models.CharField(maxlength=20) 75 76 def __str__(self): 77 return self.name 78 79 class Meta: 80 db_connection = 'q' 81 82 class QD(models.Model): 83 name = models.CharField(maxlength=20) 84 qcs = models.ManyToManyField(QC) 85 86 def __str__(self): 87 return self.name 88 89 class Meta: 90 db_connection = 'q' 91 92 API_TESTS = """ 93 94 # models can use the default connection or a named connection 95 96 # FIXME: DA is already installed 97 # models can be installed individually 98 99 # FIXME: oracle can't do ddl in a transaction, so this is going to have to 100 # be reworked to create new test databases and such as runtests does, which 101 # means its going to have to move to othertests 102 103 >>> from django.db import transaction 104 >>> transaction.enter_transaction_management() 105 >>> transaction.managed(True) 106 >>> QA._default_manager.install() 107 ([BoundStatement('CREATE TABLE "manager_schema_manipulation_qa" (...);')], []) 108 >>> QB._default_manager.install() 109 ([BoundStatement('CREATE TABLE "manager_schema_manipulation_qb" (...);')], []) 110 >>> list(QA.objects.all()) 111 [] 112 >>> QA(name="something").save() 113 >>> QA.objects.all() 114 [<QA: something>] 115 116 # models with un-installable dependencies will return a list of 117 # pending statements; these are bound to the model's connection and should 118 # be executed after all other models have been created 119 120 >>> result = PA._default_manager.install() 121 >>> result 122 ([BoundStatement('CREATE TABLE "manager_schema_manipulation_pa" (...);'), BoundStatement('CREATE INDEX manager_schema_manipulation_pa_c_id ON "manager_schema_manipulation_pa" ("c_id");')], [BoundStatement('ALTER TABLE "manager_schema_manipulation_pa" ADD CONSTRAINT "c_id_referencing_manager_schema_manipulation_pc_id" FOREIGN KEY ("c_id") REFERENCES "manager_schema_manipulation_pc" ("id");')]) 123 124 # Many-to-many statements can be generated at any time, but should not be 125 # executed until all models in the app have been created. 126 127 >>> QC._default_manager.install() 128 ([BoundStatement('CREATE TABLE "manager_schema_manipulation_qc" (...);')], []) 129 >>> QD._default_manager.install() 130 ([BoundStatement('CREATE TABLE "manager_schema_manipulation_qd" (...);')], [BoundStatement('CREATE TABLE "manager_schema_manipulation_qd_qcs" (...);')]) 131 132 """