MultipleDatabaseSupport: p5.diff
| File p5.diff, 52.8 kB (added by jpellerin@gmail.com, 2 years ago) |
|---|
-
django/db/models/base.py
old new 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
old new 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
old new 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
old new 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
old new 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
old new 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
old new 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
old new 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
old new 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
old new 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
old new 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
old new 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
old new 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
old new -
django/db/backends/ansi/creation.py
old new 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
old new 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:&
