Ticket #5461: 5461-r8194.2.diff
File 5461-r8194.2.diff, 141.3 KB (added by , 16 years ago) |
---|
-
django/core/management/commands/dbshell.py
diff -r fda9a525ebea django/core/management/commands/dbshell.py
a b 6 6 requires_model_validation = False 7 7 8 8 def handle_noargs(self, **options): 9 from django.db import runshell10 runshell()9 from django.db import connection 10 connection.client.runshell() -
django/core/management/commands/inspectdb.py
diff -r fda9a525ebea django/core/management/commands/inspectdb.py
a b 13 13 raise CommandError("Database inspection isn't supported for the currently selected database backend.") 14 14 15 15 def handle_inspection(self): 16 from django.db import connection , get_introspection_module16 from django.db import connection 17 17 import keyword 18 19 introspection_module = get_introspection_module()20 18 21 19 table2model = lambda table_name: table_name.title().replace('_', '') 22 20 … … 32 30 yield '' 33 31 yield 'from django.db import models' 34 32 yield '' 35 for table_name in introspection_module.get_table_list(cursor):33 for table_name in connection.introspection.get_table_list(cursor): 36 34 yield 'class %s(models.Model):' % table2model(table_name) 37 35 try: 38 relations = introspection_module.get_relations(cursor, table_name)36 relations = connection.introspection.get_relations(cursor, table_name) 39 37 except NotImplementedError: 40 38 relations = {} 41 39 try: 42 indexes = introspection_module.get_indexes(cursor, table_name)40 indexes = connection.introspection.get_indexes(cursor, table_name) 43 41 except NotImplementedError: 44 42 indexes = {} 45 for i, row in enumerate( introspection_module.get_table_description(cursor, table_name)):43 for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)): 46 44 att_name = row[0].lower() 47 45 comment_notes = [] # Holds Field notes, to be displayed in a Python comment. 48 46 extra_params = {} # Holds Field parameters such as 'db_column'. … … 65 63 extra_params['db_column'] = att_name 66 64 else: 67 65 try: 68 field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]66 field_type = connection.introspection.data_types_reverse[row[1]] 69 67 except KeyError: 70 68 field_type = 'TextField' 71 69 comment_notes.append('This field type is a guess.') -
django/core/management/commands/syncdb.py
diff -r fda9a525ebea django/core/management/commands/syncdb.py
a b 21 21 def handle_noargs(self, **options): 22 22 from django.db import connection, transaction, models 23 23 from django.conf import settings 24 from django.core.management.sql import table_names, installed_models, sql_model_create, sql_for_pending_references, many_to_many_sql_for_model, custom_sql_for_model, sql_indexes_for_model, emit_post_sync_signal24 from django.core.management.sql import table_names, installed_models, custom_sql_for_model, emit_post_sync_signal 25 25 26 26 verbosity = int(options.get('verbosity', 1)) 27 27 interactive = options.get('interactive') … … 73 73 print "Processing %s.%s model" % (app_name, model._meta.object_name) 74 74 if table_name_converter(model._meta.db_table) in tables: 75 75 continue 76 sql, references = sql_model_create(model, self.style, seen_models)76 sql, references = connection.creation.sql_create_model(model, self.style, seen_models) 77 77 seen_models.add(model) 78 78 created_models.add(model) 79 79 for refto, refs in references.items(): 80 80 pending_references.setdefault(refto, []).extend(refs) 81 81 if refto in seen_models: 82 sql.extend( sql_for_pending_references(refto, self.style, pending_references))83 sql.extend( sql_for_pending_references(model, self.style, pending_references))82 sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references)) 83 sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references)) 84 84 if verbosity >= 1: 85 85 print "Creating table %s" % model._meta.db_table 86 86 for statement in sql: … … 94 94 model_list = models.get_models(app) 95 95 for model in model_list: 96 96 if model in created_models: 97 sql = many_to_many_sql_for_model(model, self.style)97 sql = connection.creation.many_to_many_sql_for_model(model, self.style) 98 98 if sql: 99 99 if verbosity >= 2: 100 100 print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name) … … 140 140 app_name = app.__name__.split('.')[-2] 141 141 for model in models.get_models(app): 142 142 if model in created_models: 143 index_sql = sql_indexes_for_model(model, self.style)143 index_sql = connection.creation.sql_indexes_for_model(model, self.style) 144 144 if index_sql: 145 145 if verbosity >= 1: 146 146 print "Installing index for %s.%s model" % (app_name, model._meta.object_name) -
django/core/management/commands/testserver.py
diff -r fda9a525ebea django/core/management/commands/testserver.py
a b 18 18 19 19 def handle(self, *fixture_labels, **options): 20 20 from django.core.management import call_command 21 from django. test.utils import create_test_db21 from django.db import connection 22 22 23 23 verbosity = int(options.get('verbosity', 1)) 24 24 addrport = options.get('addrport') 25 25 26 26 # Create a test database. 27 db_name = c reate_test_db(verbosity=verbosity)27 db_name = connection.creation.create_test_db(verbosity=verbosity) 28 28 29 29 # Import the fixture data into the test database. 30 30 call_command('loaddata', *fixture_labels, **{'verbosity': verbosity}) -
django/core/management/sql.py
diff -r fda9a525ebea django/core/management/sql.py
a b 9 9 10 10 def table_names(): 11 11 "Returns a list of all table names that exist in the database." 12 from django.db import connection , get_introspection_module12 from django.db import connection 13 13 cursor = connection.cursor() 14 return set( get_introspection_module().get_table_list(cursor))14 return set(connection.introspection.get_table_list(cursor)) 15 15 16 16 def django_table_names(only_existing=False): 17 17 """ … … 65 65 66 66 def sql_create(app, style): 67 67 "Returns a list of the CREATE TABLE SQL statements for the given app." 68 from django.db import models68 from django.db import connection, models 69 69 from django.conf import settings 70 70 71 71 if settings.DATABASE_ENGINE == 'dummy': … … 85 85 pending_references = {} 86 86 87 87 for model in app_models: 88 output, references = sql_model_create(model, style, known_models)88 output, references = connection.creation.sql_create_model(model, style, known_models) 89 89 final_output.extend(output) 90 90 for refto, refs in references.items(): 91 91 pending_references.setdefault(refto, []).extend(refs) 92 92 if refto in known_models: 93 final_output.extend( sql_for_pending_references(refto, style, pending_references))94 final_output.extend( sql_for_pending_references(model, style, pending_references))93 final_output.extend(connection.creation.sql_for_pending_references(refto, style, pending_references)) 94 final_output.extend(connection.creation.sql_for_pending_references(model, style, pending_references)) 95 95 # Keep track of the fact that we've created the table for this model. 96 96 known_models.add(model) 97 97 98 98 # Create the many-to-many join tables. 99 99 for model in app_models: 100 final_output.extend( many_to_many_sql_for_model(model, style))100 final_output.extend(connection.creation.many_to_many_sql_for_model(model, style)) 101 101 102 102 # Handle references to tables that are from other apps 103 103 # but don't exist physically. … … 106 106 alter_sql = [] 107 107 for model in not_installed_models: 108 108 alter_sql.extend(['-- ' + sql for sql in 109 sql_for_pending_references(model, style, pending_references)])109 connection.creation.sql_for_pending_references(model, style, pending_references)]) 110 110 if alter_sql: 111 111 final_output.append('-- The following references should be added but depend on non-existent tables:') 112 112 final_output.extend(alter_sql) … … 115 115 116 116 def sql_delete(app, style): 117 117 "Returns a list of the DROP TABLE SQL statements for the given app." 118 from django.db import connection, models , get_introspection_module118 from django.db import connection, models 119 119 from django.db.backends.util import truncate_name 120 120 from django.contrib.contenttypes import generic 121 introspection = get_introspection_module()122 121 123 122 # This should work even if a connection isn't available 124 123 try: … … 128 127 129 128 # Figure out which tables already exist 130 129 if cursor: 131 table_names = introspection.get_table_list(cursor)130 table_names = connection.introspection.get_table_list(cursor) 132 131 else: 133 132 table_names = [] 134 133 if connection.features.uses_case_insensitive_names: … … 137 136 table_name_converter = lambda x: x 138 137 139 138 output = [] 140 qn = connection.ops.quote_name141 139 142 140 # Output DROP TABLE statements for standard application tables. 143 141 to_delete = set() … … 155 153 to_delete.add(model) 156 154 157 155 for model in app_models: 158 if cursor and table_name_converter(model._meta.db_table) in table_names: 159 # Drop the table now 160 output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'), 161 style.SQL_TABLE(qn(model._meta.db_table)))) 162 if connection.features.supports_constraints and model in references_to_delete: 163 for rel_class, f in references_to_delete[model]: 164 table = rel_class._meta.db_table 165 col = f.column 166 r_table = model._meta.db_table 167 r_col = model._meta.get_field(f.rel.field_name).column 168 r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table)))) 169 output.append('%s %s %s %s;' % \ 170 (style.SQL_KEYWORD('ALTER TABLE'), 171 style.SQL_TABLE(qn(table)), 172 style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()), 173 style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length())))) 174 del references_to_delete[model] 175 if model._meta.has_auto_field: 176 ds = connection.ops.drop_sequence_sql(model._meta.db_table) 177 if ds: 178 output.append(ds) 156 if table_name_converter(model._meta.db_table) in table_names: 157 output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style)) 179 158 180 159 # Output DROP TABLE statements for many-to-many tables. 181 160 for model in app_models: 182 161 opts = model._meta 183 162 for f in opts.local_many_to_many: 184 if not f.creates_table:185 continue186 163 if cursor and table_name_converter(f.m2m_db_table()) in table_names: 187 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'), 188 style.SQL_TABLE(qn(f.m2m_db_table())))) 189 ds = connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column)) 190 if ds: 191 output.append(ds) 164 output.extend(connection.creation.sql_destroy_many_to_many(model, f, style)) 192 165 193 166 app_label = app_models[0]._meta.app_label 194 167 … … 234 207 235 208 def sql_indexes(app, style): 236 209 "Returns a list of the CREATE INDEX SQL statements for all models in the given app." 237 from django.db import models210 from django.db import connection, models 238 211 output = [] 239 212 for model in models.get_models(app): 240 output.extend( sql_indexes_for_model(model, style))213 output.extend(connection.creation.sql_indexes_for_model(model, style)) 241 214 return output 242 215 243 216 def sql_all(app, style): 244 217 "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module." 245 218 return sql_create(app, style) + sql_custom(app, style) + sql_indexes(app, style) 246 247 def sql_model_create(model, style, known_models=set()):248 """249 Returns the SQL required to create a single model, as a tuple of:250 (list_of_sql, pending_references_dict)251 """252 from django.db import connection, models253 254 opts = model._meta255 final_output = []256 table_output = []257 pending_references = {}258 qn = connection.ops.quote_name259 inline_references = connection.features.inline_fk_references260 for f in opts.local_fields:261 col_type = f.db_type()262 tablespace = f.db_tablespace or opts.db_tablespace263 if col_type is None:264 # Skip ManyToManyFields, because they're not represented as265 # database columns in this table.266 continue267 # Make the definition (e.g. 'foo VARCHAR(30)') for this field.268 field_output = [style.SQL_FIELD(qn(f.column)),269 style.SQL_COLTYPE(col_type)]270 field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))271 if f.primary_key:272 field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))273 elif f.unique:274 field_output.append(style.SQL_KEYWORD('UNIQUE'))275 if tablespace and connection.features.supports_tablespaces and f.unique:276 # We must specify the index tablespace inline, because we277 # won't be generating a CREATE INDEX statement for this field.278 field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))279 if f.rel:280 if inline_references and f.rel.to in known_models:281 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \282 style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \283 style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +284 connection.ops.deferrable_sql()285 )286 else:287 # We haven't yet created the table to which this field288 # is related, so save it for later.289 pr = pending_references.setdefault(f.rel.to, []).append((model, f))290 table_output.append(' '.join(field_output))291 if opts.order_with_respect_to:292 table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \293 style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \294 style.SQL_KEYWORD('NULL'))295 for field_constraints in opts.unique_together:296 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \297 ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints]))298 299 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']300 for i, line in enumerate(table_output): # Combine and add commas.301 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))302 full_statement.append(')')303 if opts.db_tablespace and connection.features.supports_tablespaces:304 full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))305 full_statement.append(';')306 final_output.append('\n'.join(full_statement))307 308 if opts.has_auto_field:309 # Add any extra SQL needed to support auto-incrementing primary keys.310 auto_column = opts.auto_field.db_column or opts.auto_field.name311 autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)312 if autoinc_sql:313 for stmt in autoinc_sql:314 final_output.append(stmt)315 316 return final_output, pending_references317 318 def sql_for_pending_references(model, style, pending_references):319 """320 Returns any ALTER TABLE statements to add constraints after the fact.321 """322 from django.db import connection323 from django.db.backends.util import truncate_name324 325 qn = connection.ops.quote_name326 final_output = []327 if connection.features.supports_constraints:328 opts = model._meta329 if model in pending_references:330 for rel_class, f in pending_references[model]:331 rel_opts = rel_class._meta332 r_table = rel_opts.db_table333 r_col = f.column334 table = opts.db_table335 col = opts.get_field(f.rel.field_name).column336 # For MySQL, r_name must be unique in the first 64 characters.337 # So we are careful with character usage here.338 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))339 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \340 (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),341 qn(r_col), qn(table), qn(col),342 connection.ops.deferrable_sql()))343 del pending_references[model]344 return final_output345 346 def many_to_many_sql_for_model(model, style):347 from django.db import connection, models348 from django.contrib.contenttypes import generic349 from django.db.backends.util import truncate_name350 351 opts = model._meta352 final_output = []353 qn = connection.ops.quote_name354 inline_references = connection.features.inline_fk_references355 for f in opts.local_many_to_many:356 if f.creates_table:357 tablespace = f.db_tablespace or opts.db_tablespace358 if tablespace and connection.features.supports_tablespaces:359 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace, inline=True)360 else:361 tablespace_sql = ''362 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \363 style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']364 table_output.append(' %s %s %s%s,' %365 (style.SQL_FIELD(qn('id')),366 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),367 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),368 tablespace_sql))369 if inline_references:370 deferred = []371 table_output.append(' %s %s %s %s (%s)%s,' %372 (style.SQL_FIELD(qn(f.m2m_column_name())),373 style.SQL_COLTYPE(models.ForeignKey(model).db_type()),374 style.SQL_KEYWORD('NOT NULL REFERENCES'),375 style.SQL_TABLE(qn(opts.db_table)),376 style.SQL_FIELD(qn(opts.pk.column)),377 connection.ops.deferrable_sql()))378 table_output.append(' %s %s %s %s (%s)%s,' %379 (style.SQL_FIELD(qn(f.m2m_reverse_name())),380 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),381 style.SQL_KEYWORD('NOT NULL REFERENCES'),382 style.SQL_TABLE(qn(f.rel.to._meta.db_table)),383 style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),384 connection.ops.deferrable_sql()))385 else:386 table_output.append(' %s %s %s,' %387 (style.SQL_FIELD(qn(f.m2m_column_name())),388 style.SQL_COLTYPE(models.ForeignKey(model).db_type()),389 style.SQL_KEYWORD('NOT NULL')))390 table_output.append(' %s %s %s,' %391 (style.SQL_FIELD(qn(f.m2m_reverse_name())),392 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),393 style.SQL_KEYWORD('NOT NULL')))394 deferred = [395 (f.m2m_db_table(), f.m2m_column_name(), opts.db_table,396 opts.pk.column),397 ( f.m2m_db_table(), f.m2m_reverse_name(),398 f.rel.to._meta.db_table, f.rel.to._meta.pk.column)399 ]400 table_output.append(' %s (%s, %s)%s' %401 (style.SQL_KEYWORD('UNIQUE'),402 style.SQL_FIELD(qn(f.m2m_column_name())),403 style.SQL_FIELD(qn(f.m2m_reverse_name())),404 tablespace_sql))405 table_output.append(')')406 if opts.db_tablespace and connection.features.supports_tablespaces:407 # f.db_tablespace is only for indices, so ignore its value here.408 table_output.append(connection.ops.tablespace_sql(opts.db_tablespace))409 table_output.append(';')410 final_output.append('\n'.join(table_output))411 412 for r_table, r_col, table, col in deferred:413 r_name = '%s_refs_%s_%x' % (r_col, col,414 abs(hash((r_table, table))))415 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %416 (qn(r_table),417 truncate_name(r_name, connection.ops.max_name_length()),418 qn(r_col), qn(table), qn(col),419 connection.ops.deferrable_sql()))420 421 # Add any extra SQL needed to support auto-incrementing PKs422 autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table(), 'id')423 if autoinc_sql:424 for stmt in autoinc_sql:425 final_output.append(stmt)426 427 return final_output428 219 429 220 def custom_sql_for_model(model, style): 430 221 from django.db import models … … 461 252 462 253 return output 463 254 464 def sql_indexes_for_model(model, style):465 "Returns the CREATE INDEX SQL statements for a single model"466 from django.db import connection467 output = []468 469 qn = connection.ops.quote_name470 for f in model._meta.local_fields:471 if f.db_index and not f.unique:472 tablespace = f.db_tablespace or model._meta.db_tablespace473 if tablespace and connection.features.supports_tablespaces:474 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)475 else:476 tablespace_sql = ''477 output.append(478 style.SQL_KEYWORD('CREATE INDEX') + ' ' + \479 style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \480 style.SQL_KEYWORD('ON') + ' ' + \481 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \482 "(%s)" % style.SQL_FIELD(qn(f.column)) + \483 "%s;" % tablespace_sql484 )485 return output486 255 487 256 def emit_post_sync_signal(created_models, verbosity, interactive): 488 257 from django.db import models -
django/core/management/validation.py
diff -r fda9a525ebea django/core/management/validation.py
a b 61 61 if f.db_index not in (None, True, False): 62 62 e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name) 63 63 64 # Check that max_length <= 255 if using older MySQL versions. 65 if settings.DATABASE_ENGINE == 'mysql': 66 db_version = connection.get_server_version() 67 if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255: 68 e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]]))) 64 # Perform any backend-specific field validation. 65 connection.validation.validate_field(e, opts, f) 69 66 70 67 # Check to see if the related field will clash with any existing 71 68 # fields, m2m fields, m2m related objects or related objects -
django/db/__init__.py
diff -r fda9a525ebea django/db/__init__.py
a b 15 15 # backends that ships with Django, so look there first. 16 16 _import_path = 'django.db.backends.' 17 17 backend = __import__('%s%s.base' % (_import_path, settings.DATABASE_ENGINE), {}, {}, ['']) 18 creation = __import__('%s%s.creation' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])19 18 except ImportError, e: 20 19 # If the import failed, we might be looking for a database backend 21 20 # distributed external to Django. So we'll try that next. 22 21 try: 23 22 _import_path = '' 24 23 backend = __import__('%s.base' % settings.DATABASE_ENGINE, {}, {}, ['']) 25 creation = __import__('%s.creation' % settings.DATABASE_ENGINE, {}, {}, [''])26 24 except ImportError, e_user: 27 25 # The database backend wasn't found. Display a helpful error message 28 26 # listing all possible (built-in) database backends. … … 30 28 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')] 31 29 available_backends.sort() 32 30 if settings.DATABASE_ENGINE not in available_backends: 33 raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s " % \34 (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends )))31 raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s\nError was: %s" % \ 32 (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends, e_user))) 35 33 else: 36 34 raise # If there's some other error, this must be an error in Django itself. 37 38 def _import_database_module(import_path='', module_name=''):39 """Lazily import a database module when requested."""40 return __import__('%s%s.%s' % (import_path, settings.DATABASE_ENGINE, module_name), {}, {}, [''])41 42 # We don't want to import the introspect module unless someone asks for it, so43 # lazily load it on demmand.44 get_introspection_module = curry(_import_database_module, _import_path, 'introspection')45 46 def get_creation_module():47 return creation48 49 # We want runshell() to work the same way, but we have to treat it a50 # little differently (since it just runs instead of returning a module like51 # the above) and wrap the lazily-loaded runshell() method.52 runshell = lambda: _import_database_module(_import_path, "client").runshell()53 35 54 36 # Convenient aliases for backend bits. 55 37 connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS) -
django/db/backends/__init__.py
diff -r fda9a525ebea django/db/backends/__init__.py
a b 325 325 """ 326 326 return self.year_lookup_bounds(value) 327 327 328 class BaseDatabaseIntrospection(object): 329 """ 330 This class encapsulates all backend-specific introspection utilities 331 """ 332 data_types_reverse = {} 333 334 class BaseDatabaseClient(object): 335 """ 336 This class encapsualtes all backend-specific methods for opening a 337 client shell 338 """ 339 def runshell(self): 340 raise NotImplementedError() 341 342 class BaseDatabaseValidation(object): 343 """ 344 This class encapsualtes all backend-specific model validation. 345 """ 346 def validate_field(self, errors, opts, f): 347 "By default, there is no backend-specific validation" 348 pass 349 No newline at end of file -
django/db/backends/creation.py
diff -r fda9a525ebea django/db/backends/creation.py
a b 1 class BaseCreation(object): 1 import sys 2 import time 3 4 from django.conf import settings 5 from django.core.management import call_command 6 7 # The prefix to put on the default database name when creating 8 # the test database. 9 TEST_DATABASE_PREFIX = 'test_' 10 11 class BaseDatabaseCreation(object): 2 12 """ 3 13 This class encapsulates all backend-specific differences that pertain to 4 14 database *creation*, such as the column types to use for particular Django 5 15 Fields. 6 16 """ 7 pass 17 data_types = {} 18 19 def __init__(self, ops, features): 20 self.ops = ops 21 self.features = features 22 23 def sql_create_model(self, model, style, known_models=set()): 24 """ 25 Returns the SQL required to create a single model, as a tuple of: 26 (list_of_sql, pending_references_dict) 27 """ 28 from django.db import models 29 30 opts = model._meta 31 final_output = [] 32 table_output = [] 33 pending_references = {} 34 qn = self.ops.quote_name 35 inline_references = self.features.inline_fk_references 36 for f in opts.local_fields: 37 col_type = f.db_type() 38 tablespace = f.db_tablespace or opts.db_tablespace 39 if col_type is None: 40 # Skip ManyToManyFields, because they're not represented as 41 # database columns in this table. 42 continue 43 # Make the definition (e.g. 'foo VARCHAR(30)') for this field. 44 field_output = [style.SQL_FIELD(qn(f.column)), 45 style.SQL_COLTYPE(col_type)] 46 field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or ''))) 47 if f.primary_key: 48 field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 49 elif f.unique: 50 field_output.append(style.SQL_KEYWORD('UNIQUE')) 51 if tablespace and self.features.supports_tablespaces and f.unique: 52 # We must specify the index tablespace inline, because we 53 # won't be generating a CREATE INDEX statement for this field. 54 field_output.append(self.ops.tablespace_sql(tablespace, inline=True)) 55 if f.rel: 56 if inline_references and f.rel.to in known_models: 57 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \ 58 style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \ 59 style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' + 60 self.ops.deferrable_sql() 61 ) 62 else: 63 # We haven't yet created the table to which this field 64 # is related, so save it for later. 65 pr = pending_references.setdefault(f.rel.to, []).append((model, f)) 66 table_output.append(' '.join(field_output)) 67 if opts.order_with_respect_to: 68 table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \ 69 style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \ 70 style.SQL_KEYWORD('NULL')) 71 for field_constraints in opts.unique_together: 72 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ 73 ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints])) 74 75 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' ('] 76 for i, line in enumerate(table_output): # Combine and add commas. 77 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 78 full_statement.append(')') 79 if opts.db_tablespace and self.features.supports_tablespaces: 80 full_statement.append(self.ops.tablespace_sql(opts.db_tablespace)) 81 full_statement.append(';') 82 final_output.append('\n'.join(full_statement)) 83 84 if opts.has_auto_field: 85 # Add any extra SQL needed to support auto-incrementing primary keys. 86 auto_column = opts.auto_field.db_column or opts.auto_field.name 87 autoinc_sql = self.ops.autoinc_sql(opts.db_table, auto_column) 88 if autoinc_sql: 89 for stmt in autoinc_sql: 90 final_output.append(stmt) 91 92 return final_output, pending_references 93 94 def sql_for_pending_references(self, model, style, pending_references): 95 """ 96 Returns any ALTER TABLE statements to add constraints after the fact. 97 """ 98 from django.db.backends.util import truncate_name 99 100 qn = self.ops.quote_name 101 final_output = [] 102 if self.features.supports_constraints: 103 opts = model._meta 104 if model in pending_references: 105 for rel_class, f in pending_references[model]: 106 rel_opts = rel_class._meta 107 r_table = rel_opts.db_table 108 r_col = f.column 109 table = opts.db_table 110 col = opts.get_field(f.rel.field_name).column 111 # For MySQL, r_name must be unique in the first 64 characters. 112 # So we are careful with character usage here. 113 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table)))) 114 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \ 115 (qn(r_table), truncate_name(r_name, self.ops.max_name_length()), 116 qn(r_col), qn(table), qn(col), 117 self.ops.deferrable_sql())) 118 del pending_references[model] 119 return final_output 120 121 def many_to_many_sql_for_model(self, model, style): 122 output = [] 123 for f in model._meta.local_many_to_many: 124 output.extend(self.sql_for_many_to_many_field(model, f, style)) 125 return output 126 127 def sql_for_many_to_many_field(self, model, f, style): 128 "Return the CREATE TABLE statements for a single m2m field" 129 from django.db import models 130 from django.db.backends.util import truncate_name 131 132 output = [] 133 if f.creates_table: 134 opts = model._meta 135 inline_references = self.features.inline_fk_references 136 qn = self.ops.quote_name 137 tablespace = f.db_tablespace or opts.db_tablespace 138 if tablespace and self.features.supports_tablespaces: 139 tablespace_sql = ' ' + self.ops.tablespace_sql(tablespace, inline=True) 140 else: 141 tablespace_sql = '' 142 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ 143 style.SQL_TABLE(qn(f.m2m_db_table())) + ' ('] 144 table_output.append(' %s %s %s%s,' % 145 (style.SQL_FIELD(qn('id')), 146 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()), 147 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'), 148 tablespace_sql)) 149 if inline_references: 150 deferred = [] 151 table_output.append(' %s %s %s %s (%s)%s,' % 152 (style.SQL_FIELD(qn(f.m2m_column_name())), 153 style.SQL_COLTYPE(models.ForeignKey(model).db_type()), 154 style.SQL_KEYWORD('NOT NULL REFERENCES'), 155 style.SQL_TABLE(qn(opts.db_table)), 156 style.SQL_FIELD(qn(opts.pk.column)), 157 self.ops.deferrable_sql())) 158 table_output.append(' %s %s %s %s (%s)%s,' % 159 (style.SQL_FIELD(qn(f.m2m_reverse_name())), 160 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()), 161 style.SQL_KEYWORD('NOT NULL REFERENCES'), 162 style.SQL_TABLE(qn(f.rel.to._meta.db_table)), 163 style.SQL_FIELD(qn(f.rel.to._meta.pk.column)), 164 self.ops.deferrable_sql())) 165 else: 166 table_output.append(' %s %s %s,' % 167 (style.SQL_FIELD(qn(f.m2m_column_name())), 168 style.SQL_COLTYPE(models.ForeignKey(model).db_type()), 169 style.SQL_KEYWORD('NOT NULL'))) 170 table_output.append(' %s %s %s,' % 171 (style.SQL_FIELD(qn(f.m2m_reverse_name())), 172 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()), 173 style.SQL_KEYWORD('NOT NULL'))) 174 deferred = [ 175 (f.m2m_db_table(), f.m2m_column_name(), opts.db_table, 176 opts.pk.column), 177 ( f.m2m_db_table(), f.m2m_reverse_name(), 178 f.rel.to._meta.db_table, f.rel.to._meta.pk.column) 179 ] 180 table_output.append(' %s (%s, %s)%s' % 181 (style.SQL_KEYWORD('UNIQUE'), 182 style.SQL_FIELD(qn(f.m2m_column_name())), 183 style.SQL_FIELD(qn(f.m2m_reverse_name())), 184 tablespace_sql)) 185 table_output.append(')') 186 if opts.db_tablespace and self.features.supports_tablespaces: 187 # f.db_tablespace is only for indices, so ignore its value here. 188 table_output.append(self.ops.tablespace_sql(opts.db_tablespace)) 189 table_output.append(';') 190 output.append('\n'.join(table_output)) 191 192 for r_table, r_col, table, col in deferred: 193 r_name = '%s_refs_%s_%x' % (r_col, col, 194 abs(hash((r_table, table)))) 195 output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 196 (qn(r_table), 197 truncate_name(r_name, self.ops.max_name_length()), 198 qn(r_col), qn(table), qn(col), 199 self.ops.deferrable_sql())) 200 201 # Add any extra SQL needed to support auto-incrementing PKs 202 autoinc_sql = self.ops.autoinc_sql(f.m2m_db_table(), 'id') 203 if autoinc_sql: 204 for stmt in autoinc_sql: 205 output.append(stmt) 206 return output 207 208 def sql_indexes_for_model(self, model, style): 209 "Returns the CREATE INDEX SQL statements for a single model" 210 output = [] 211 for f in model._meta.local_fields: 212 output.extend(self.sql_indexes_for_field(model, f, style)) 213 return output 214 215 def sql_indexes_for_field(self, model, f, style): 216 "Return the CREATE INDEX SQL statements for a single model field" 217 if f.db_index and not f.unique: 218 qn = self.ops.quote_name 219 tablespace = f.db_tablespace or model._meta.db_tablespace 220 if tablespace and self.features.supports_tablespaces: 221 tablespace_sql = ' ' + self.ops.tablespace_sql(tablespace) 222 else: 223 tablespace_sql = '' 224 output = [style.SQL_KEYWORD('CREATE INDEX') + ' ' + 225 style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + 226 style.SQL_KEYWORD('ON') + ' ' + 227 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + 228 "(%s)" % style.SQL_FIELD(qn(f.column)) + 229 "%s;" % tablespace_sql] 230 else: 231 output = [] 232 return output 233 234 def sql_destroy_model(self, model, references_to_delete, style): 235 "Return the DROP TABLE and restraint dropping statements for a single model" 236 # Drop the table now 237 qn = self.ops.quote_name 238 output = ['%s %s;' % (style.SQL_KEYWORD('DROP TABLE'), 239 style.SQL_TABLE(qn(model._meta.db_table)))] 240 if self.features.supports_constraints and model in references_to_delete: 241 for rel_class, f in references_to_delete[model]: 242 table = rel_class._meta.db_table 243 col = f.column 244 r_table = model._meta.db_table 245 r_col = model._meta.get_field(f.rel.field_name).column 246 r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table)))) 247 output.append('%s %s %s %s;' % \ 248 (style.SQL_KEYWORD('ALTER TABLE'), 249 style.SQL_TABLE(qn(table)), 250 style.SQL_KEYWORD(self.ops.drop_foreignkey_sql()), 251 style.SQL_FIELD(truncate_name(r_name, self.ops.max_name_length())))) 252 del references_to_delete[model] 253 if model._meta.has_auto_field: 254 ds = self.ops.drop_sequence_sql(model._meta.db_table) 255 if ds: 256 output.append(ds) 257 return output 258 259 def sql_destroy_many_to_many(self, model, f, style): 260 "Returns the DROP TABLE statements for a single m2m field" 261 qn = self.ops.quote_name 262 output = [] 263 if f.creates_table: 264 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'), 265 style.SQL_TABLE(qn(f.m2m_db_table())))) 266 ds = connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column)) 267 if ds: 268 output.append(ds) 269 return output 270 271 def create_test_db(self, verbosity=1, autoclobber=False): 272 """ 273 Creates a test database, prompting the user for confirmation if the 274 database already exists. Returns the name of the test database created. 275 """ 276 from django.db import connection 277 if verbosity >= 1: 278 print "Creating test database..." 279 280 test_database_name = self._create_test_db(connection, verbosity, autoclobber) 281 282 connection.close() 283 settings.DATABASE_NAME = test_database_name 284 285 call_command('syncdb', verbosity=verbosity, interactive=False) 286 287 if settings.CACHE_BACKEND.startswith('db://'): 288 cache_name = settings.CACHE_BACKEND[len('db://'):] 289 call_command('createcachetable', cache_name) 290 291 # Get a cursor (even though we don't need one yet). This has 292 # the side effect of initializing the test database. 293 cursor = connection.cursor() 294 295 return test_database_name 296 297 def _create_test_db(self, connection, verbosity, autoclobber): 298 suffix = self._creation_suffix() 299 300 if settings.TEST_DATABASE_NAME: 301 test_database_name = settings.TEST_DATABASE_NAME 302 else: 303 test_database_name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 304 305 qn = self.ops.quote_name 306 307 # Create the test database and connect to it. We need to autocommit 308 # if the database supports it because PostgreSQL doesn't allow 309 # CREATE/DROP DATABASE statements within transactions. 310 cursor = connection.cursor() 311 self._set_autocommit(connection) 312 try: 313 cursor.execute("CREATE DATABASE %s %s" % (qn(test_database_name), suffix)) 314 except Exception, e: 315 sys.stderr.write("Got an error creating the test database: %s\n" % e) 316 if not autoclobber: 317 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % test_database_name) 318 if autoclobber or confirm == 'yes': 319 try: 320 if verbosity >= 1: 321 print "Destroying old test database..." 322 cursor.execute("DROP DATABASE %s" % qn(test_database_name)) 323 if verbosity >= 1: 324 print "Creating test database..." 325 cursor.execute("CREATE DATABASE %s %s" % (qn(test_database_name), suffix)) 326 except Exception, e: 327 sys.stderr.write("Got an error recreating the test database: %s\n" % e) 328 sys.exit(2) 329 else: 330 print "Tests cancelled." 331 sys.exit(1) 332 333 return test_database_name 334 335 def destroy_test_db(self, old_database_name, verbosity=1): 336 """ 337 Destroy a test database, prompting the user for confirmation if the 338 database already exists. Returns the name of the test database created. 339 """ 340 from django.db import connection 341 if verbosity >= 1: 342 print "Destroying test database..." 343 connection.close() 344 test_database_name = settings.DATABASE_NAME 345 settings.DATABASE_NAME = old_database_name 346 347 self._destroy_test_db(connection, test_database_name, verbosity) 348 349 def _destroy_test_db(self, connection, test_database_name, verbosity): 350 # Remove the test database to clean up after 351 # ourselves. Connect to the previous database (not the test database) 352 # to do so, because it's not allowed to delete a database while being 353 # connected to it. 354 cursor = connection.cursor() 355 self._set_autocommit(connection) 356 time.sleep(1) # To avoid "database is being accessed by other users" errors. 357 cursor.execute("DROP DATABASE %s" % self.ops.quote_name(test_database_name)) 358 connection.close() 359 360 def _set_autocommit(self, connection): 361 "Make sure a connection is in autocommit mode." 362 if hasattr(connection.connection, "autocommit"): 363 if callable(connection.connection.autocommit): 364 connection.connection.autocommit(True) 365 else: 366 connection.connection.autocommit = True 367 elif hasattr(connection.connection, "set_isolation_level"): 368 connection.connection.set_isolation_level(0) 369 370 def _creation_suffix(self): 371 "SQL to append to the end of the test table creation statements" 372 return '' 373 -
django/db/backends/dummy/base.py
diff -r fda9a525ebea django/db/backends/dummy/base.py
a b 8 8 """ 9 9 10 10 from django.core.exceptions import ImproperlyConfigured 11 from django.db.backends import BaseDatabaseFeatures, BaseDatabaseOperations 11 from django.db.backends import BaseDatabaseClient 12 from django.db.backends import BaseDatabaseFeatures 13 from django.db.backends import BaseDatabaseIntrospection 14 from django.db.backends import BaseDatabaseOperations 15 from django.db.backends import BaseDatabaseValidation 16 from django.db.backends.creation import BaseDatabaseCreation 12 17 13 18 def complain(*args, **kwargs): 14 19 raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet." … … 25 30 class DatabaseOperations(BaseDatabaseOperations): 26 31 quote_name = complain 27 32 33 class DatabaseClient(BaseDatabaseClient): 34 runshell = complain 35 36 class DatabaseCreation(BaseDatabaseCreation): 37 pass 38 39 class DatabaseIntrospection(BaseDatabaseIntrospection): 40 get_table_list = complain 41 get_table_description = complain 42 get_relations = complain 43 get_indexes = complain 44 45 class DatabaseValidation(BaseDatabaseValidation): 46 pass 47 28 48 class DatabaseWrapper(object): 29 49 features = BaseDatabaseFeatures() 30 50 ops = DatabaseOperations() 51 client = DatabaseClient() 52 creation = DatabaseCreation(ops, features) 53 introspection = DatabaseIntrospection() 54 validation = DatabaseValidation() 55 31 56 operators = {} 32 57 cursor = complain 33 58 _commit = complain -
django/db/backends/dummy/client.py
diff -r fda9a525ebea django/db/backends/dummy/client.py
a b 1 from django.db.backends.dummy.base import complain2 3 runshell = complain -
django/db/backends/dummy/creation.py
diff -r fda9a525ebea django/db/backends/dummy/creation.py
a b 1 DATA_TYPES = {} -
django/db/backends/dummy/introspection.py
diff -r fda9a525ebea django/db/backends/dummy/introspection.py
a b 1 from django.db.backends.dummy.base import complain2 3 get_table_list = complain4 get_table_description = complain5 get_relations = complain6 get_indexes = complain7 8 DATA_TYPES_REVERSE = {} -
django/db/backends/mysql/base.py
diff -r fda9a525ebea django/db/backends/mysql/base.py
a b 4 4 Requires MySQLdb: http://sourceforge.net/projects/mysql-python 5 5 """ 6 6 7 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 7 from django.db.backends import BaseDatabaseFeatures 8 from django.db.backends import BaseDatabaseOperations 9 from django.db.backends import BaseDatabaseWrapper 10 from django.db.backends import util 11 from django.db.backends.mysql.client import DatabaseClient 12 from django.db.backends.mysql.creation import DatabaseCreation 13 from django.db.backends.mysql.introspection import DatabaseIntrospection 14 from django.db.backends.mysql.validation import DatabaseValidation 15 8 16 try: 9 17 import MySQLdb as Database 10 18 except ImportError, e: … … 144 152 class DatabaseWrapper(BaseDatabaseWrapper): 145 153 features = DatabaseFeatures() 146 154 ops = DatabaseOperations() 155 client = DatabaseClient() 156 creation = DatabaseCreation(ops, features) 157 introspection = DatabaseIntrospection(ops) 158 validation = DatabaseValidation() 159 147 160 operators = { 148 161 'exact': '= BINARY %s', 149 162 'iexact': 'LIKE %s', -
django/db/backends/mysql/client.py
diff -r fda9a525ebea django/db/backends/mysql/client.py
a b 1 from django.db.backends import BaseDatabaseClient 1 2 from django.conf import settings 2 3 import os 3 4 4 def runshell(): 5 args = [''] 6 db = settings.DATABASE_OPTIONS.get('db', settings.DATABASE_NAME) 7 user = settings.DATABASE_OPTIONS.get('user', settings.DATABASE_USER) 8 passwd = settings.DATABASE_OPTIONS.get('passwd', settings.DATABASE_PASSWORD) 9 host = settings.DATABASE_OPTIONS.get('host', settings.DATABASE_HOST) 10 port = settings.DATABASE_OPTIONS.get('port', settings.DATABASE_PORT) 11 defaults_file = settings.DATABASE_OPTIONS.get('read_default_file') 12 # Seems to be no good way to set sql_mode with CLI 5 class DatabaseClient(BaseDatabaseClient): 6 def runshell(self): 7 args = [''] 8 db = settings.DATABASE_OPTIONS.get('db', settings.DATABASE_NAME) 9 user = settings.DATABASE_OPTIONS.get('user', settings.DATABASE_USER) 10 passwd = settings.DATABASE_OPTIONS.get('passwd', settings.DATABASE_PASSWORD) 11 host = settings.DATABASE_OPTIONS.get('host', settings.DATABASE_HOST) 12 port = settings.DATABASE_OPTIONS.get('port', settings.DATABASE_PORT) 13 defaults_file = settings.DATABASE_OPTIONS.get('read_default_file') 14 # Seems to be no good way to set sql_mode with CLI 13 15 14 if defaults_file:15 args += ["--defaults-file=%s" % defaults_file]16 if user:17 args += ["--user=%s" % user]18 if passwd:19 args += ["--password=%s" % passwd]20 if host:21 args += ["--host=%s" % host]22 if port:23 args += ["--port=%s" % port]24 if db:25 args += [db]16 if defaults_file: 17 args += ["--defaults-file=%s" % defaults_file] 18 if user: 19 args += ["--user=%s" % user] 20 if passwd: 21 args += ["--password=%s" % passwd] 22 if host: 23 args += ["--host=%s" % host] 24 if port: 25 args += ["--port=%s" % port] 26 if db: 27 args += [db] 26 28 27 os.execvp('mysql', args)29 os.execvp('mysql', args) -
django/db/backends/mysql/creation.py
diff -r fda9a525ebea django/db/backends/mysql/creation.py
a b 1 # This dictionary maps Field objects to their associated MySQL column 2 # types, as strings. Column-type strings can contain format strings; they'll 3 # be interpolated against the values of Field.__dict__ before being output. 4 # If a column type is set to None, it won't be included in the output. 5 DATA_TYPES = { 6 'AutoField': 'integer AUTO_INCREMENT', 7 'BooleanField': 'bool', 8 'CharField': 'varchar(%(max_length)s)', 9 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 10 'DateField': 'date', 11 'DateTimeField': 'datetime', 12 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 13 'FileField': 'varchar(%(max_length)s)', 14 'FilePathField': 'varchar(%(max_length)s)', 15 'FloatField': 'double precision', 16 'IntegerField': 'integer', 17 'IPAddressField': 'char(15)', 18 'NullBooleanField': 'bool', 19 'OneToOneField': 'integer', 20 'PhoneNumberField': 'varchar(20)', 21 'PositiveIntegerField': 'integer UNSIGNED', 22 'PositiveSmallIntegerField': 'smallint UNSIGNED', 23 'SlugField': 'varchar(%(max_length)s)', 24 'SmallIntegerField': 'smallint', 25 'TextField': 'longtext', 26 'TimeField': 'time', 27 'USStateField': 'varchar(2)', 28 } 1 from django.conf import settings 2 from django.db.backends.creation import BaseDatabaseCreation 3 4 class DatabaseCreation(BaseDatabaseCreation): 5 # This dictionary maps Field objects to their associated MySQL column 6 # types, as strings. Column-type strings can contain format strings; they'll 7 # be interpolated against the values of Field.__dict__ before being output. 8 # If a column type is set to None, it won't be included in the output. 9 data_types = { 10 'AutoField': 'integer AUTO_INCREMENT', 11 'BooleanField': 'bool', 12 'CharField': 'varchar(%(max_length)s)', 13 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 14 'DateField': 'date', 15 'DateTimeField': 'datetime', 16 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 17 'FileField': 'varchar(%(max_length)s)', 18 'FilePathField': 'varchar(%(max_length)s)', 19 'FloatField': 'double precision', 20 'IntegerField': 'integer', 21 'IPAddressField': 'char(15)', 22 'NullBooleanField': 'bool', 23 'OneToOneField': 'integer', 24 'PhoneNumberField': 'varchar(20)', 25 'PositiveIntegerField': 'integer UNSIGNED', 26 'PositiveSmallIntegerField': 'smallint UNSIGNED', 27 'SlugField': 'varchar(%(max_length)s)', 28 'SmallIntegerField': 'smallint', 29 'TextField': 'longtext', 30 'TimeField': 'time', 31 'USStateField': 'varchar(2)', 32 } 33 34 def _creation_suffix(self): 35 suffix = [] 36 if settings.TEST_DATABASE_CHARSET: 37 suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET) 38 if settings.TEST_DATABASE_COLLATION: 39 suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION) 40 return ' '.join(suffix) -
django/db/backends/mysql/introspection.py
diff -r fda9a525ebea django/db/backends/mysql/introspection.py
a b 1 from django.db.backends .mysql.base import DatabaseOperations1 from django.db.backends import BaseDatabaseIntrospection 2 2 from MySQLdb import ProgrammingError, OperationalError 3 3 from MySQLdb.constants import FIELD_TYPE 4 4 import re 5 5 6 quote_name = DatabaseOperations().quote_name7 6 foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 8 7 9 def get_table_list(cursor): 10 "Returns a list of table names in the current database." 11 cursor.execute("SHOW TABLES") 12 return [row[0] for row in cursor.fetchall()] 8 class DatabaseIntrospection(BaseDatabaseIntrospection): 9 data_types_reverse = { 10 FIELD_TYPE.BLOB: 'TextField', 11 FIELD_TYPE.CHAR: 'CharField', 12 FIELD_TYPE.DECIMAL: 'DecimalField', 13 FIELD_TYPE.DATE: 'DateField', 14 FIELD_TYPE.DATETIME: 'DateTimeField', 15 FIELD_TYPE.DOUBLE: 'FloatField', 16 FIELD_TYPE.FLOAT: 'FloatField', 17 FIELD_TYPE.INT24: 'IntegerField', 18 FIELD_TYPE.LONG: 'IntegerField', 19 FIELD_TYPE.LONGLONG: 'IntegerField', 20 FIELD_TYPE.SHORT: 'IntegerField', 21 FIELD_TYPE.STRING: 'CharField', 22 FIELD_TYPE.TIMESTAMP: 'DateTimeField', 23 FIELD_TYPE.TINY: 'IntegerField', 24 FIELD_TYPE.TINY_BLOB: 'TextField', 25 FIELD_TYPE.MEDIUM_BLOB: 'TextField', 26 FIELD_TYPE.LONG_BLOB: 'TextField', 27 FIELD_TYPE.VAR_STRING: 'CharField', 28 } 13 29 14 def get_table_description(cursor, table_name): 15 "Returns a description of the table, with the DB-API cursor.description interface." 16 cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name)) 17 return cursor.description 30 def __init__(self, ops): 31 self.ops = ops 32 33 def get_table_list(self, cursor): 34 "Returns a list of table names in the current database." 35 cursor.execute("SHOW TABLES") 36 return [row[0] for row in cursor.fetchall()] 18 37 19 def _name_to_index(cursor, table_name): 20 """ 21 Returns a dictionary of {field_name: field_index} for the given table. 22 Indexes are 0-based. 23 """ 24 return dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name))]) 38 def get_table_description(self, cursor, table_name): 39 "Returns a description of the table, with the DB-API cursor.description interface." 40 cursor.execute("SELECT * FROM %s LIMIT 1" % self.ops.quote_name(table_name)) 41 return cursor.description 25 42 26 def get_relations(cursor, table_name): 27 """ 28 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 29 representing all relationships to the given table. Indexes are 0-based. 30 """ 31 my_field_dict = _name_to_index(cursor, table_name) 32 constraints = [] 33 relations = {} 34 try: 35 # This should work for MySQL 5.0. 36 cursor.execute(""" 37 SELECT column_name, referenced_table_name, referenced_column_name 38 FROM information_schema.key_column_usage 39 WHERE table_name = %s 40 AND table_schema = DATABASE() 41 AND referenced_table_name IS NOT NULL 42 AND referenced_column_name IS NOT NULL""", [table_name]) 43 constraints.extend(cursor.fetchall()) 44 except (ProgrammingError, OperationalError): 45 # Fall back to "SHOW CREATE TABLE", for previous MySQL versions. 46 # Go through all constraints and save the equal matches. 47 cursor.execute("SHOW CREATE TABLE %s" % quote_name(table_name)) 43 def _name_to_index(self, cursor, table_name): 44 """ 45 Returns a dictionary of {field_name: field_index} for the given table. 46 Indexes are 0-based. 47 """ 48 return dict([(d[0], i) for i, d in enumerate(self.get_table_description(cursor, table_name))]) 49 50 def get_relations(self, cursor, table_name): 51 """ 52 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 53 representing all relationships to the given table. Indexes are 0-based. 54 """ 55 my_field_dict = self._name_to_index(cursor, table_name) 56 constraints = [] 57 relations = {} 58 try: 59 # This should work for MySQL 5.0. 60 cursor.execute(""" 61 SELECT column_name, referenced_table_name, referenced_column_name 62 FROM information_schema.key_column_usage 63 WHERE table_name = %s 64 AND table_schema = DATABASE() 65 AND referenced_table_name IS NOT NULL 66 AND referenced_column_name IS NOT NULL""", [table_name]) 67 constraints.extend(cursor.fetchall()) 68 except (ProgrammingError, OperationalError): 69 # Fall back to "SHOW CREATE TABLE", for previous MySQL versions. 70 # Go through all constraints and save the equal matches. 71 cursor.execute("SHOW CREATE TABLE %s" % self.ops.quote_name(table_name)) 72 for row in cursor.fetchall(): 73 pos = 0 74 while True: 75 match = foreign_key_re.search(row[1], pos) 76 if match == None: 77 break 78 pos = match.end() 79 constraints.append(match.groups()) 80 81 for my_fieldname, other_table, other_field in constraints: 82 other_field_index = self._name_to_index(cursor, other_table)[other_field] 83 my_field_index = my_field_dict[my_fieldname] 84 relations[my_field_index] = (other_field_index, other_table) 85 86 return relations 87 88 def get_indexes(self, cursor, table_name): 89 """ 90 Returns a dictionary of fieldname -> infodict for the given table, 91 where each infodict is in the format: 92 {'primary_key': boolean representing whether it's the primary key, 93 'unique': boolean representing whether it's a unique index} 94 """ 95 cursor.execute("SHOW INDEX FROM %s" % self.ops.quote_name(table_name)) 96 indexes = {} 48 97 for row in cursor.fetchall(): 49 pos = 0 50 while True: 51 match = foreign_key_re.search(row[1], pos) 52 if match == None: 53 break 54 pos = match.end() 55 constraints.append(match.groups()) 98 indexes[row[4]] = {'primary_key': (row[2] == 'PRIMARY'), 'unique': not bool(row[1])} 99 return indexes 56 100 57 for my_fieldname, other_table, other_field in constraints:58 other_field_index = _name_to_index(cursor, other_table)[other_field]59 my_field_index = my_field_dict[my_fieldname]60 relations[my_field_index] = (other_field_index, other_table)61 62 return relations63 64 def get_indexes(cursor, table_name):65 """66 Returns a dictionary of fieldname -> infodict for the given table,67 where each infodict is in the format:68 {'primary_key': boolean representing whether it's the primary key,69 'unique': boolean representing whether it's a unique index}70 """71 cursor.execute("SHOW INDEX FROM %s" % quote_name(table_name))72 indexes = {}73 for row in cursor.fetchall():74 indexes[row[4]] = {'primary_key': (row[2] == 'PRIMARY'), 'unique': not bool(row[1])}75 return indexes76 77 DATA_TYPES_REVERSE = {78 FIELD_TYPE.BLOB: 'TextField',79 FIELD_TYPE.CHAR: 'CharField',80 FIELD_TYPE.DECIMAL: 'DecimalField',81 FIELD_TYPE.DATE: 'DateField',82 FIELD_TYPE.DATETIME: 'DateTimeField',83 FIELD_TYPE.DOUBLE: 'FloatField',84 FIELD_TYPE.FLOAT: 'FloatField',85 FIELD_TYPE.INT24: 'IntegerField',86 FIELD_TYPE.LONG: 'IntegerField',87 FIELD_TYPE.LONGLONG: 'IntegerField',88 FIELD_TYPE.SHORT: 'IntegerField',89 FIELD_TYPE.STRING: 'CharField',90 FIELD_TYPE.TIMESTAMP: 'DateTimeField',91 FIELD_TYPE.TINY: 'IntegerField',92 FIELD_TYPE.TINY_BLOB: 'TextField',93 FIELD_TYPE.MEDIUM_BLOB: 'TextField',94 FIELD_TYPE.LONG_BLOB: 'TextField',95 FIELD_TYPE.VAR_STRING: 'CharField',96 } -
django/db/backends/oracle/base.py
diff -r fda9a525ebea django/db/backends/oracle/base.py
a b 8 8 import datetime 9 9 import time 10 10 11 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 11 from django.db.backends import BaseDatabaseFeatures 12 from django.db.backends import BaseDatabaseOperations 13 from django.db.backends import BaseDatabaseWrapper 14 from django.db.backends import BaseDatabaseValidation 15 from django.db.backends import util 12 16 from django.db.backends.oracle import query 17 from django.db.backends.oracle.client import DatabaseClient 18 from django.db.backends.oracle.creation import DatabaseCreation 19 from django.db.backends.oracle.introspection import DatabaseIntrospection 13 20 from django.utils.encoding import smart_str, force_unicode 14 21 15 22 # Oracle takes client-side character set encoding from the environment. … … 194 201 return [first % value, second % value] 195 202 196 203 204 class DatabaseValidation(BaseDatabaseValidation): 205 pass 197 206 198 207 class DatabaseWrapper(BaseDatabaseWrapper): 199 208 features = DatabaseFeatures() 200 209 ops = DatabaseOperations() 210 client = DatabaseClient() 211 creation = DatabaseCreation(ops, features) 212 introspection = DatabaseIntrospection(ops) 213 validation = DatabaseValidation() 214 201 215 operators = { 202 216 'exact': '= %s', 203 217 'iexact': '= UPPER(%s)', -
django/db/backends/oracle/client.py
diff -r fda9a525ebea django/db/backends/oracle/client.py
a b 1 from django.db.backends import BaseDatabaseClient 1 2 from django.conf import settings 2 3 import os 3 4 4 def runshell(): 5 dsn = settings.DATABASE_USER 6 if settings.DATABASE_PASSWORD: 7 dsn += "/%s" % settings.DATABASE_PASSWORD 8 if settings.DATABASE_NAME: 9 dsn += "@%s" % settings.DATABASE_NAME 10 args = ["sqlplus", "-L", dsn] 11 os.execvp("sqlplus", args) 5 class DatabaseClient(BaseDatabaseClient): 6 def runshell(self): 7 dsn = settings.DATABASE_USER 8 if settings.DATABASE_PASSWORD: 9 dsn += "/%s" % settings.DATABASE_PASSWORD 10 if settings.DATABASE_NAME: 11 dsn += "@%s" % settings.DATABASE_NAME 12 args = ["sqlplus", "-L", dsn] 13 os.execvp("sqlplus", args) -
django/db/backends/oracle/creation.py
diff -r fda9a525ebea django/db/backends/oracle/creation.py
a b 1 1 import sys, time 2 from django.conf import settings 2 3 from django.core import management 3 4 # This dictionary maps Field objects to their associated Oracle column 5 # types, as strings. Column-type strings can contain format strings; they'll 6 # be interpolated against the values of Field.__dict__ before being output. 7 # If a column type is set to None, it won't be included in the output. 8 # 9 # Any format strings starting with "qn_" are quoted before being used in the 10 # output (the "qn_" prefix is stripped before the lookup is performed. 11 12 DATA_TYPES = { 13 'AutoField': 'NUMBER(11)', 14 'BooleanField': 'NUMBER(1) CHECK (%(qn_column)s IN (0,1))', 15 'CharField': 'NVARCHAR2(%(max_length)s)', 16 'CommaSeparatedIntegerField': 'VARCHAR2(%(max_length)s)', 17 'DateField': 'DATE', 18 'DateTimeField': 'TIMESTAMP', 19 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)', 20 'FileField': 'NVARCHAR2(%(max_length)s)', 21 'FilePathField': 'NVARCHAR2(%(max_length)s)', 22 'FloatField': 'DOUBLE PRECISION', 23 'IntegerField': 'NUMBER(11)', 24 'IPAddressField': 'VARCHAR2(15)', 25 'NullBooleanField': 'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL))', 26 'OneToOneField': 'NUMBER(11)', 27 'PhoneNumberField': 'VARCHAR2(20)', 28 'PositiveIntegerField': 'NUMBER(11) CHECK (%(qn_column)s >= 0)', 29 'PositiveSmallIntegerField': 'NUMBER(11) CHECK (%(qn_column)s >= 0)', 30 'SlugField': 'NVARCHAR2(50)', 31 'SmallIntegerField': 'NUMBER(11)', 32 'TextField': 'NCLOB', 33 'TimeField': 'TIMESTAMP', 34 'URLField': 'VARCHAR2(%(max_length)s)', 35 'USStateField': 'CHAR(2)', 36 } 4 from django.db.backends.creation import BaseDatabaseCreation 37 5 38 6 TEST_DATABASE_PREFIX = 'test_' 39 7 PASSWORD = 'Im_a_lumberjack' 40 REMEMBER = {}41 8 42 def create_test_db(settings, connection, verbosity=1, autoclobber=False): 43 TEST_DATABASE_NAME = _test_database_name(settings) 44 TEST_DATABASE_USER = _test_database_user(settings) 45 TEST_DATABASE_PASSWD = _test_database_passwd(settings) 46 TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings) 47 TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings) 9 class DatabaseCreation(BaseDatabaseCreation): 10 # This dictionary maps Field objects to their associated Oracle column 11 # types, as strings. Column-type strings can contain format strings; they'll 12 # be interpolated against the values of Field.__dict__ before being output. 13 # If a column type is set to None, it won't be included in the output. 14 # 15 # Any format strings starting with "qn_" are quoted before being used in the 16 # output (the "qn_" prefix is stripped before the lookup is performed. 48 17 49 parameters = { 50 'dbname': TEST_DATABASE_NAME, 51 'user': TEST_DATABASE_USER, 52 'password': TEST_DATABASE_PASSWD, 53 'tblspace': TEST_DATABASE_TBLSPACE, 54 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, 55 } 18 data_types = { 19 'AutoField': 'NUMBER(11)', 20 'BooleanField': 'NUMBER(1) CHECK (%(qn_column)s IN (0,1))', 21 'CharField': 'NVARCHAR2(%(max_length)s)', 22 'CommaSeparatedIntegerField': 'VARCHAR2(%(max_length)s)', 23 'DateField': 'DATE', 24 'DateTimeField': 'TIMESTAMP', 25 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)', 26 'FileField': 'NVARCHAR2(%(max_length)s)', 27 'FilePathField': 'NVARCHAR2(%(max_length)s)', 28 'FloatField': 'DOUBLE PRECISION', 29 'IntegerField': 'NUMBER(11)', 30 'IPAddressField': 'VARCHAR2(15)', 31 'NullBooleanField': 'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL))', 32 'OneToOneField': 'NUMBER(11)', 33 'PhoneNumberField': 'VARCHAR2(20)', 34 'PositiveIntegerField': 'NUMBER(11) CHECK (%(qn_column)s >= 0)', 35 'PositiveSmallIntegerField': 'NUMBER(11) CHECK (%(qn_column)s >= 0)', 36 'SlugField': 'NVARCHAR2(50)', 37 'SmallIntegerField': 'NUMBER(11)', 38 'TextField': 'NCLOB', 39 'TimeField': 'TIMESTAMP', 40 'URLField': 'VARCHAR2(%(max_length)s)', 41 'USStateField': 'CHAR(2)', 42 } 43 44 def _create_test_db(self, connection, verbosity, autoclobber): 45 TEST_DATABASE_NAME = self._test_database_name(settings) 46 TEST_DATABASE_USER = self._test_database_user(settings) 47 TEST_DATABASE_PASSWD = self._test_database_passwd(settings) 48 TEST_DATABASE_TBLSPACE = self._test_database_tblspace(settings) 49 TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp(settings) 56 50 57 REMEMBER['user'] = settings.DATABASE_USER 58 REMEMBER['passwd'] = settings.DATABASE_PASSWORD 51 parameters = { 52 'dbname': TEST_DATABASE_NAME, 53 'user': TEST_DATABASE_USER, 54 'password': TEST_DATABASE_PASSWD, 55 'tblspace': TEST_DATABASE_TBLSPACE, 56 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, 57 } 59 58 60 cursor = connection.cursor() 61 if _test_database_create(settings): 62 if verbosity >= 1: 63 print 'Creating test database...' 59 self.remember['user'] = settings.DATABASE_USER 60 self.remember['passwd'] = settings.DATABASE_PASSWORD 61 62 cursor = connection.cursor() 63 if self._test_database_create(settings): 64 if verbosity >= 1: 65 print 'Creating test database...' 66 try: 67 self._execute_test_db_creation(cursor, parameters, verbosity) 68 except Exception, e: 69 sys.stderr.write("Got an error creating the test database: %s\n" % e) 70 if not autoclobber: 71 confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) 72 if autoclobber or confirm == 'yes': 73 try: 74 if verbosity >= 1: 75 print "Destroying old test database..." 76 self._execute_test_db_destruction(cursor, parameters, verbosity) 77 if verbosity >= 1: 78 print "Creating test database..." 79 self._execute_test_db_creation(cursor, parameters, verbosity) 80 except Exception, e: 81 sys.stderr.write("Got an error recreating the test database: %s\n" % e) 82 sys.exit(2) 83 else: 84 print "Tests cancelled." 85 sys.exit(1) 86 87 if self._test_user_create(settings): 88 if verbosity >= 1: 89 print "Creating test user..." 90 try: 91 self._create_test_user(cursor, parameters, verbosity) 92 except Exception, e: 93 sys.stderr.write("Got an error creating the test user: %s\n" % e) 94 if not autoclobber: 95 confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER) 96 if autoclobber or confirm == 'yes': 97 try: 98 if verbosity >= 1: 99 print "Destroying old test user..." 100 self._destroy_test_user(cursor, parameters, verbosity) 101 if verbosity >= 1: 102 print "Creating test user..." 103 self._create_test_user(cursor, parameters, verbosity) 104 except Exception, e: 105 sys.stderr.write("Got an error recreating the test user: %s\n" % e) 106 sys.exit(2) 107 else: 108 print "Tests cancelled." 109 sys.exit(1) 110 111 settings.DATABASE_USER = TEST_DATABASE_USER 112 settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD 113 114 return TEST_DATABASE_NAME 115 116 def _destroy_test_db(self, connection, test_database_name, verbosity=1): 117 """ 118 Destroy a test database, prompting the user for confirmation if the 119 database already exists. Returns the name of the test database created. 120 """ 121 TEST_DATABASE_NAME = self._test_database_name(settings) 122 TEST_DATABASE_USER = self._test_database_user(settings) 123 TEST_DATABASE_PASSWD = self._test_database_passwd(settings) 124 TEST_DATABASE_TBLSPACE = self._test_database_tblspace(settings) 125 TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp(settings) 126 127 settings.DATABASE_USER = self.remember['user'] 128 settings.DATABASE_PASSWORD = self.remember['passwd'] 129 130 parameters = { 131 'dbname': TEST_DATABASE_NAME, 132 'user': TEST_DATABASE_USER, 133 'password': TEST_DATABASE_PASSWD, 134 'tblspace': TEST_DATABASE_TBLSPACE, 135 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, 136 } 137 138 self.remember['user'] = settings.DATABASE_USER 139 self.remember['passwd'] = settings.DATABASE_PASSWORD 140 141 cursor = connection.cursor() 142 time.sleep(1) # To avoid "database is being accessed by other users" errors. 143 if self._test_user_create(settings): 144 if verbosity >= 1: 145 print 'Destroying test user...' 146 self._destroy_test_user(cursor, parameters, verbosity) 147 if self._test_database_create(settings): 148 if verbosity >= 1: 149 print 'Destroying test database tables...' 150 self._execute_test_db_destruction(cursor, parameters, verbosity) 151 connection.close() 152 153 def _execute_test_db_creation(cursor, parameters, verbosity): 154 if verbosity >= 2: 155 print "_create_test_db(): dbname = %s" % parameters['dbname'] 156 statements = [ 157 """CREATE TABLESPACE %(tblspace)s 158 DATAFILE '%(tblspace)s.dbf' SIZE 20M 159 REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M 160 """, 161 """CREATE TEMPORARY TABLESPACE %(tblspace_temp)s 162 TEMPFILE '%(tblspace_temp)s.dbf' SIZE 20M 163 REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M 164 """, 165 ] 166 _execute_statements(cursor, statements, parameters, verbosity) 167 168 def _create_test_user(cursor, parameters, verbosity): 169 if verbosity >= 2: 170 print "_create_test_user(): username = %s" % parameters['user'] 171 statements = [ 172 """CREATE USER %(user)s 173 IDENTIFIED BY %(password)s 174 DEFAULT TABLESPACE %(tblspace)s 175 TEMPORARY TABLESPACE %(tblspace_temp)s 176 """, 177 """GRANT CONNECT, RESOURCE TO %(user)s""", 178 ] 179 _execute_statements(cursor, statements, parameters, verbosity) 180 181 def _execute_test_db_destruction(cursor, parameters, verbosity): 182 if verbosity >= 2: 183 print "_execute_test_db_destruction(): dbname=%s" % parameters['dbname'] 184 statements = [ 185 'DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 186 'DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 187 ] 188 _execute_statements(cursor, statements, parameters, verbosity) 189 190 def _destroy_test_user(cursor, parameters, verbosity): 191 if verbosity >= 2: 192 print "_destroy_test_user(): user=%s" % parameters['user'] 193 print "Be patient. This can take some time..." 194 statements = [ 195 'DROP USER %(user)s CASCADE', 196 ] 197 _execute_statements(cursor, statements, parameters, verbosity) 198 199 def _execute_statements(cursor, statements, parameters, verbosity): 200 for template in statements: 201 stmt = template % parameters 202 if verbosity >= 2: 203 print stmt 204 try: 205 cursor.execute(stmt) 206 except Exception, err: 207 sys.stderr.write("Failed (%s)\n" % (err)) 208 raise 209 210 def _test_database_name(settings): 211 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 64 212 try: 65 _create_test_db(cursor, parameters, verbosity) 66 except Exception, e: 67 sys.stderr.write("Got an error creating the test database: %s\n" % e) 68 if not autoclobber: 69 confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) 70 if autoclobber or confirm == 'yes': 71 try: 72 if verbosity >= 1: 73 print "Destroying old test database..." 74 _destroy_test_db(cursor, parameters, verbosity) 75 if verbosity >= 1: 76 print "Creating test database..." 77 _create_test_db(cursor, parameters, verbosity) 78 except Exception, e: 79 sys.stderr.write("Got an error recreating the test database: %s\n" % e) 80 sys.exit(2) 213 if settings.TEST_DATABASE_NAME: 214 name = settings.TEST_DATABASE_NAME 215 except AttributeError: 216 pass 217 except: 218 raise 219 return name 220 221 def _test_database_create(settings): 222 name = True 223 try: 224 if settings.TEST_DATABASE_CREATE: 225 name = True 81 226 else: 82 print "Tests cancelled." 83 sys.exit(1) 227 name = False 228 except AttributeError: 229 pass 230 except: 231 raise 232 return name 84 233 85 if _test_user_create(settings): 86 if verbosity >= 1: 87 print "Creating test user..." 234 def _test_user_create(settings): 235 name = True 88 236 try: 89 _create_test_user(cursor, parameters, verbosity) 90 except Exception, e: 91 sys.stderr.write("Got an error creating the test user: %s\n" % e) 92 if not autoclobber: 93 confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER) 94 if autoclobber or confirm == 'yes': 95 try: 96 if verbosity >= 1: 97 print "Destroying old test user..." 98 _destroy_test_user(cursor, parameters, verbosity) 99 if verbosity >= 1: 100 print "Creating test user..." 101 _create_test_user(cursor, parameters, verbosity) 102 except Exception, e: 103 sys.stderr.write("Got an error recreating the test user: %s\n" % e) 104 sys.exit(2) 237 if settings.TEST_USER_CREATE: 238 name = True 105 239 else: 106 print "Tests cancelled." 107 sys.exit(1) 240 name = False 241 except AttributeError: 242 pass 243 except: 244 raise 245 return name 108 246 109 connection.close() 110 settings.DATABASE_USER = TEST_DATABASE_USER 111 settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD 247 def _test_database_user(settings): 248 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 249 try: 250 if settings.TEST_DATABASE_USER: 251 name = settings.TEST_DATABASE_USER 252 except AttributeError: 253 pass 254 except: 255 raise 256 return name 112 257 113 management.call_command('syncdb', verbosity=verbosity, interactive=False) 258 def _test_database_passwd(settings): 259 name = PASSWORD 260 try: 261 if settings.TEST_DATABASE_PASSWD: 262 name = settings.TEST_DATABASE_PASSWD 263 except AttributeError: 264 pass 265 except: 266 raise 267 return name 114 268 115 # Get a cursor (even though we don't need one yet). This has 116 # the side effect of initializing the test database. 117 cursor = connection.cursor() 269 def _test_database_tblspace(settings): 270 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 271 try: 272 if settings.TEST_DATABASE_TBLSPACE: 273 name = settings.TEST_DATABASE_TBLSPACE 274 except AttributeError: 275 pass 276 except: 277 raise 278 return name 118 279 119 def destroy_test_db(settings, connection, old_database_name, verbosity=1): 120 connection.close() 121 122 TEST_DATABASE_NAME = _test_database_name(settings) 123 TEST_DATABASE_USER = _test_database_user(settings) 124 TEST_DATABASE_PASSWD = _test_database_passwd(settings) 125 TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings) 126 TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings) 127 128 settings.DATABASE_NAME = old_database_name 129 settings.DATABASE_USER = REMEMBER['user'] 130 settings.DATABASE_PASSWORD = REMEMBER['passwd'] 131 132 parameters = { 133 'dbname': TEST_DATABASE_NAME, 134 'user': TEST_DATABASE_USER, 135 'password': TEST_DATABASE_PASSWD, 136 'tblspace': TEST_DATABASE_TBLSPACE, 137 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, 138 } 139 140 REMEMBER['user'] = settings.DATABASE_USER 141 REMEMBER['passwd'] = settings.DATABASE_PASSWORD 142 143 cursor = connection.cursor() 144 time.sleep(1) # To avoid "database is being accessed by other users" errors. 145 if _test_user_create(settings): 146 if verbosity >= 1: 147 print 'Destroying test user...' 148 _destroy_test_user(cursor, parameters, verbosity) 149 if _test_database_create(settings): 150 if verbosity >= 1: 151 print 'Destroying test database...' 152 _destroy_test_db(cursor, parameters, verbosity) 153 connection.close() 154 155 def _create_test_db(cursor, parameters, verbosity): 156 if verbosity >= 2: 157 print "_create_test_db(): dbname = %s" % parameters['dbname'] 158 statements = [ 159 """CREATE TABLESPACE %(tblspace)s 160 DATAFILE '%(tblspace)s.dbf' SIZE 20M 161 REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M 162 """, 163 """CREATE TEMPORARY TABLESPACE %(tblspace_temp)s 164 TEMPFILE '%(tblspace_temp)s.dbf' SIZE 20M 165 REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M 166 """, 167 ] 168 _execute_statements(cursor, statements, parameters, verbosity) 169 170 def _create_test_user(cursor, parameters, verbosity): 171 if verbosity >= 2: 172 print "_create_test_user(): username = %s" % parameters['user'] 173 statements = [ 174 """CREATE USER %(user)s 175 IDENTIFIED BY %(password)s 176 DEFAULT TABLESPACE %(tblspace)s 177 TEMPORARY TABLESPACE %(tblspace_temp)s 178 """, 179 """GRANT CONNECT, RESOURCE TO %(user)s""", 180 ] 181 _execute_statements(cursor, statements, parameters, verbosity) 182 183 def _destroy_test_db(cursor, parameters, verbosity): 184 if verbosity >= 2: 185 print "_destroy_test_db(): dbname=%s" % parameters['dbname'] 186 statements = [ 187 'DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 188 'DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 189 ] 190 _execute_statements(cursor, statements, parameters, verbosity) 191 192 def _destroy_test_user(cursor, parameters, verbosity): 193 if verbosity >= 2: 194 print "_destroy_test_user(): user=%s" % parameters['user'] 195 print "Be patient. This can take some time..." 196 statements = [ 197 'DROP USER %(user)s CASCADE', 198 ] 199 _execute_statements(cursor, statements, parameters, verbosity) 200 201 def _execute_statements(cursor, statements, parameters, verbosity): 202 for template in statements: 203 stmt = template % parameters 204 if verbosity >= 2: 205 print stmt 280 def _test_database_tblspace_tmp(settings): 281 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp' 206 282 try: 207 cursor.execute(stmt) 208 except Exception, err: 209 sys.stderr.write("Failed (%s)\n" % (err)) 283 if settings.TEST_DATABASE_TBLSPACE_TMP: 284 name = settings.TEST_DATABASE_TBLSPACE_TMP 285 except AttributeError: 286 pass 287 except: 210 288 raise 211 212 def _test_database_name(settings): 213 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 214 try: 215 if settings.TEST_DATABASE_NAME: 216 name = settings.TEST_DATABASE_NAME 217 except AttributeError: 218 pass 219 except: 220 raise 221 return name 222 223 def _test_database_create(settings): 224 name = True 225 try: 226 if settings.TEST_DATABASE_CREATE: 227 name = True 228 else: 229 name = False 230 except AttributeError: 231 pass 232 except: 233 raise 234 return name 235 236 def _test_user_create(settings): 237 name = True 238 try: 239 if settings.TEST_USER_CREATE: 240 name = True 241 else: 242 name = False 243 except AttributeError: 244 pass 245 except: 246 raise 247 return name 248 249 def _test_database_user(settings): 250 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 251 try: 252 if settings.TEST_DATABASE_USER: 253 name = settings.TEST_DATABASE_USER 254 except AttributeError: 255 pass 256 except: 257 raise 258 return name 259 260 def _test_database_passwd(settings): 261 name = PASSWORD 262 try: 263 if settings.TEST_DATABASE_PASSWD: 264 name = settings.TEST_DATABASE_PASSWD 265 except AttributeError: 266 pass 267 except: 268 raise 269 return name 270 271 def _test_database_tblspace(settings): 272 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 273 try: 274 if settings.TEST_DATABASE_TBLSPACE: 275 name = settings.TEST_DATABASE_TBLSPACE 276 except AttributeError: 277 pass 278 except: 279 raise 280 return name 281 282 def _test_database_tblspace_tmp(settings): 283 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp' 284 try: 285 if settings.TEST_DATABASE_TBLSPACE_TMP: 286 name = settings.TEST_DATABASE_TBLSPACE_TMP 287 except AttributeError: 288 pass 289 except: 290 raise 291 return name 289 return name -
django/db/backends/oracle/introspection.py
diff -r fda9a525ebea django/db/backends/oracle/introspection.py
a b 1 from django.db.backends.oracle.base import DatabaseOperations 1 from django.db.backends import BaseDatabaseIntrospection 2 import cx_Oracle 2 3 import re 3 import cx_Oracle4 4 5 quote_name = DatabaseOperations().quote_name6 5 foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 7 6 8 def get_table_list(cursor): 9 "Returns a list of table names in the current database." 10 cursor.execute("SELECT TABLE_NAME FROM USER_TABLES") 11 return [row[0].upper() for row in cursor.fetchall()] 7 class DatabaseIntrospection(BaseDatabaseIntrospection): 8 # Maps type objects to Django Field types. 9 data_types_reverse = { 10 cx_Oracle.CLOB: 'TextField', 11 cx_Oracle.DATETIME: 'DateTimeField', 12 cx_Oracle.FIXED_CHAR: 'CharField', 13 cx_Oracle.NCLOB: 'TextField', 14 cx_Oracle.NUMBER: 'DecimalField', 15 cx_Oracle.STRING: 'CharField', 16 cx_Oracle.TIMESTAMP: 'DateTimeField', 17 } 12 18 13 def get_table_description(cursor, table_name): 14 "Returns a description of the table, with the DB-API cursor.description interface." 15 cursor.execute("SELECT * FROM %s WHERE ROWNUM < 2" % quote_name(table_name)) 16 return cursor.description 19 def __init__(self, ops): 20 self.ops = ops 21 22 def get_table_list(self, cursor): 23 "Returns a list of table names in the current database." 24 cursor.execute("SELECT TABLE_NAME FROM USER_TABLES") 25 return [row[0].upper() for row in cursor.fetchall()] 17 26 18 def _name_to_index(cursor, table_name): 19 """ 20 Returns a dictionary of {field_name: field_index} for the given table. 21 Indexes are 0-based. 22 """ 23 return dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name))]) 27 def get_table_description(self, cursor, table_name): 28 "Returns a description of the table, with the DB-API cursor.description interface." 29 cursor.execute("SELECT * FROM %s WHERE ROWNUM < 2" % self.ops.quote_name(table_name)) 30 return cursor.description 24 31 25 def get_relations(cursor, table_name): 26 """ 27 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 28 representing all relationships to the given table. Indexes are 0-based. 29 """ 30 cursor.execute(""" 31 SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1 32 FROM user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb, 33 user_tab_cols ta, user_tab_cols tb 34 WHERE user_constraints.table_name = %s AND 35 ta.table_name = %s AND 36 ta.column_name = ca.column_name AND 37 ca.table_name = %s AND 38 user_constraints.constraint_name = ca.constraint_name AND 39 user_constraints.r_constraint_name = cb.constraint_name AND 40 cb.table_name = tb.table_name AND 41 cb.column_name = tb.column_name AND 42 ca.position = cb.position""", [table_name, table_name, table_name]) 32 def _name_to_index(self, cursor, table_name): 33 """ 34 Returns a dictionary of {field_name: field_index} for the given table. 35 Indexes are 0-based. 36 """ 37 return dict([(d[0], i) for i, d in enumerate(self.get_table_description(cursor, table_name))]) 43 38 44 relations = {} 45 for row in cursor.fetchall(): 46 relations[row[0]] = (row[2], row[1]) 47 return relations 39 def get_relations(self, cursor, table_name): 40 """ 41 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 42 representing all relationships to the given table. Indexes are 0-based. 43 """ 44 cursor.execute(""" 45 SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1 46 FROM user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb, 47 user_tab_cols ta, user_tab_cols tb 48 WHERE user_constraints.table_name = %s AND 49 ta.table_name = %s AND 50 ta.column_name = ca.column_name AND 51 ca.table_name = %s AND 52 user_constraints.constraint_name = ca.constraint_name AND 53 user_constraints.r_constraint_name = cb.constraint_name AND 54 cb.table_name = tb.table_name AND 55 cb.column_name = tb.column_name AND 56 ca.position = cb.position""", [table_name, table_name, table_name]) 48 57 49 def get_indexes(cursor, table_name): 50 """ 51 Returns a dictionary of fieldname -> infodict for the given table, 52 where each infodict is in the format: 53 {'primary_key': boolean representing whether it's the primary key, 54 'unique': boolean representing whether it's a unique index} 55 """ 56 # This query retrieves each index on the given table, including the 57 # first associated field name 58 # "We were in the nick of time; you were in great peril!" 59 sql = """ 60 WITH primarycols AS ( 61 SELECT user_cons_columns.table_name, user_cons_columns.column_name, 1 AS PRIMARYCOL 62 FROM user_cons_columns, user_constraints 63 WHERE user_cons_columns.constraint_name = user_constraints.constraint_name AND 64 user_constraints.constraint_type = 'P' AND 65 user_cons_columns.table_name = %s), 66 uniquecols AS ( 67 SELECT user_ind_columns.table_name, user_ind_columns.column_name, 1 AS UNIQUECOL 68 FROM user_indexes, user_ind_columns 69 WHERE uniqueness = 'UNIQUE' AND 70 user_indexes.index_name = user_ind_columns.index_name AND 71 user_ind_columns.table_name = %s) 72 SELECT allcols.column_name, primarycols.primarycol, uniquecols.UNIQUECOL 73 FROM (SELECT column_name FROM primarycols UNION SELECT column_name FROM 74 uniquecols) allcols, 75 primarycols, uniquecols 76 WHERE allcols.column_name = primarycols.column_name (+) AND 77 allcols.column_name = uniquecols.column_name (+) 78 """ 79 cursor.execute(sql, [table_name, table_name]) 80 indexes = {} 81 for row in cursor.fetchall(): 82 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 83 # a string of space-separated integers. This designates the field 84 # indexes (1-based) of the fields that have indexes on the table. 85 # Here, we skip any indexes across multiple fields. 86 indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]} 87 return indexes 58 relations = {} 59 for row in cursor.fetchall(): 60 relations[row[0]] = (row[2], row[1]) 61 return relations 88 62 89 # Maps type objects to Django Field types. 90 DATA_TYPES_REVERSE = { 91 cx_Oracle.CLOB: 'TextField', 92 cx_Oracle.DATETIME: 'DateTimeField', 93 cx_Oracle.FIXED_CHAR: 'CharField', 94 cx_Oracle.NCLOB: 'TextField', 95 cx_Oracle.NUMBER: 'DecimalField', 96 cx_Oracle.STRING: 'CharField', 97 cx_Oracle.TIMESTAMP: 'DateTimeField', 98 } 63 def get_indexes(self, cursor, table_name): 64 """ 65 Returns a dictionary of fieldname -> infodict for the given table, 66 where each infodict is in the format: 67 {'primary_key': boolean representing whether it's the primary key, 68 'unique': boolean representing whether it's a unique index} 69 """ 70 # This query retrieves each index on the given table, including the 71 # first associated field name 72 # "We were in the nick of time; you were in great peril!" 73 sql = """ 74 WITH primarycols AS ( 75 SELECT user_cons_columns.table_name, user_cons_columns.column_name, 1 AS PRIMARYCOL 76 FROM user_cons_columns, user_constraints 77 WHERE user_cons_columns.constraint_name = user_constraints.constraint_name AND 78 user_constraints.constraint_type = 'P' AND 79 user_cons_columns.table_name = %s), 80 uniquecols AS ( 81 SELECT user_ind_columns.table_name, user_ind_columns.column_name, 1 AS UNIQUECOL 82 FROM user_indexes, user_ind_columns 83 WHERE uniqueness = 'UNIQUE' AND 84 user_indexes.index_name = user_ind_columns.index_name AND 85 user_ind_columns.table_name = %s) 86 SELECT allcols.column_name, primarycols.primarycol, uniquecols.UNIQUECOL 87 FROM (SELECT column_name FROM primarycols UNION SELECT column_name FROM 88 uniquecols) allcols, 89 primarycols, uniquecols 90 WHERE allcols.column_name = primarycols.column_name (+) AND 91 allcols.column_name = uniquecols.column_name (+) 92 """ 93 cursor.execute(sql, [table_name, table_name]) 94 indexes = {} 95 for row in cursor.fetchall(): 96 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 97 # a string of space-separated integers. This designates the field 98 # indexes (1-based) of the fields that have indexes on the table. 99 # Here, we skip any indexes across multiple fields. 100 indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]} 101 return indexes 102 -
django/db/backends/postgresql/base.py
diff -r fda9a525ebea django/db/backends/postgresql/base.py
a b 4 4 Requires psycopg 1: http://initd.org/projects/psycopg1 5 5 """ 6 6 7 from django.db.backends import BaseDatabaseFeatures 8 from django.db.backends import BaseDatabaseValidation 9 from django.db.backends import BaseDatabaseWrapper 10 from django.db.backends import util 11 from django.db.backends.postgresql.client import DatabaseClient 12 from django.db.backends.postgresql.creation import DatabaseCreation 13 from django.db.backends.postgresql.introspection import DatabaseIntrospection 14 from django.db.backends.postgresql.operations import DatabaseOperations 7 15 from django.utils.encoding import smart_str, smart_unicode 8 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, util 9 from django.db.backends.postgresql.operations import DatabaseOperations 16 10 17 try: 11 18 import psycopg as Database 12 19 except ImportError, e: … … 62 69 class DatabaseFeatures(BaseDatabaseFeatures): 63 70 pass # This backend uses all the defaults. 64 71 72 class DatabaseValidation(BaseDatabaseValidation): 73 pass 74 65 75 class DatabaseWrapper(BaseDatabaseWrapper): 66 76 features = DatabaseFeatures() 67 77 ops = DatabaseOperations() 78 client = DatabaseClient() 79 creation = DatabaseCreation(ops, features) 80 introspection = DatabaseIntrospection(ops) 81 validation = DatabaseValidation() 82 68 83 operators = { 69 84 'exact': '= %s', 70 85 'iexact': 'ILIKE %s', -
django/db/backends/postgresql/client.py
diff -r fda9a525ebea django/db/backends/postgresql/client.py
a b 1 from django.db.backends import BaseDatabaseClient 1 2 from django.conf import settings 2 3 import os 3 4 4 def runshell(): 5 args = ['psql'] 6 if settings.DATABASE_USER: 7 args += ["-U", settings.DATABASE_USER] 8 if settings.DATABASE_PASSWORD: 9 args += ["-W"] 10 if settings.DATABASE_HOST: 11 args.extend(["-h", settings.DATABASE_HOST]) 12 if settings.DATABASE_PORT: 13 args.extend(["-p", str(settings.DATABASE_PORT)]) 14 args += [settings.DATABASE_NAME] 15 os.execvp('psql', args) 5 class DatabaseClient(BaseDatabaseClient): 6 def runshell(self): 7 args = ['psql'] 8 if settings.DATABASE_USER: 9 args += ["-U", settings.DATABASE_USER] 10 if settings.DATABASE_PASSWORD: 11 args += ["-W"] 12 if settings.DATABASE_HOST: 13 args.extend(["-h", settings.DATABASE_HOST]) 14 if settings.DATABASE_PORT: 15 args.extend(["-p", str(settings.DATABASE_PORT)]) 16 args += [settings.DATABASE_NAME] 17 os.execvp('psql', args) -
django/db/backends/postgresql/creation.py
diff -r fda9a525ebea django/db/backends/postgresql/creation.py
a b 1 # This dictionary maps Field objects to their associated PostgreSQL column 2 # types, as strings. Column-type strings can contain format strings; they'll 3 # be interpolated against the values of Field.__dict__ before being output. 4 # If a column type is set to None, it won't be included in the output. 5 DATA_TYPES = { 6 'AutoField': 'serial', 7 'BooleanField': 'boolean', 8 'CharField': 'varchar(%(max_length)s)', 9 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 10 'DateField': 'date', 11 'DateTimeField': 'timestamp with time zone', 12 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 13 'FileField': 'varchar(%(max_length)s)', 14 'FilePathField': 'varchar(%(max_length)s)', 15 'FloatField': 'double precision', 16 'IntegerField': 'integer', 17 'IPAddressField': 'inet', 18 'NullBooleanField': 'boolean', 19 'OneToOneField': 'integer', 20 'PhoneNumberField': 'varchar(20)', 21 'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)', 22 'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)', 23 'SlugField': 'varchar(%(max_length)s)', 24 'SmallIntegerField': 'smallint', 25 'TextField': 'text', 26 'TimeField': 'time', 27 'USStateField': 'varchar(2)', 28 } 1 from django.conf import settings 2 from django.db.backends.creation import BaseDatabaseCreation 3 4 class DatabaseCreation(BaseDatabaseCreation): 5 # This dictionary maps Field objects to their associated PostgreSQL column 6 # types, as strings. Column-type strings can contain format strings; they'll 7 # be interpolated against the values of Field.__dict__ before being output. 8 # If a column type is set to None, it won't be included in the output. 9 data_types = { 10 'AutoField': 'serial', 11 'BooleanField': 'boolean', 12 'CharField': 'varchar(%(max_length)s)', 13 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 14 'DateField': 'date', 15 'DateTimeField': 'timestamp with time zone', 16 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 17 'FileField': 'varchar(%(max_length)s)', 18 'FilePathField': 'varchar(%(max_length)s)', 19 'FloatField': 'double precision', 20 'IntegerField': 'integer', 21 'IPAddressField': 'inet', 22 'NullBooleanField': 'boolean', 23 'OneToOneField': 'integer', 24 'PhoneNumberField': 'varchar(20)', 25 'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)', 26 'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)', 27 'SlugField': 'varchar(%(max_length)s)', 28 'SmallIntegerField': 'smallint', 29 'TextField': 'text', 30 'TimeField': 'time', 31 'USStateField': 'varchar(2)', 32 } 33 34 def _creation_suffix(self): 35 assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time." 36 if settings.TEST_DATABASE_CHARSET: 37 return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET 38 return '' -
django/db/backends/postgresql/introspection.py
diff -r fda9a525ebea django/db/backends/postgresql/introspection.py
a b 1 from django.db.backends .postgresql.base import DatabaseOperations1 from django.db.backends import BaseDatabaseIntrospection 2 2 3 quote_name = DatabaseOperations().quote_name 3 class DatabaseIntrospection(BaseDatabaseIntrospection): 4 # Maps type codes to Django Field types. 5 data_types_reverse = { 6 16: 'BooleanField', 7 21: 'SmallIntegerField', 8 23: 'IntegerField', 9 25: 'TextField', 10 701: 'FloatField', 11 869: 'IPAddressField', 12 1043: 'CharField', 13 1082: 'DateField', 14 1083: 'TimeField', 15 1114: 'DateTimeField', 16 1184: 'DateTimeField', 17 1266: 'TimeField', 18 1700: 'DecimalField', 19 } 20 21 def __init__(self, ops): 22 self.ops = ops 23 24 def get_table_list(self, cursor): 25 "Returns a list of table names in the current database." 26 cursor.execute(""" 27 SELECT c.relname 28 FROM pg_catalog.pg_class c 29 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 30 WHERE c.relkind IN ('r', 'v', '') 31 AND n.nspname NOT IN ('pg_catalog', 'pg_toast') 32 AND pg_catalog.pg_table_is_visible(c.oid)""") 33 return [row[0] for row in cursor.fetchall()] 4 34 5 def get_table_list(cursor): 6 "Returns a list of table names in the current database." 7 cursor.execute(""" 8 SELECT c.relname 9 FROM pg_catalog.pg_class c 10 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 11 WHERE c.relkind IN ('r', 'v', '') 12 AND n.nspname NOT IN ('pg_catalog', 'pg_toast') 13 AND pg_catalog.pg_table_is_visible(c.oid)""") 14 return [row[0] for row in cursor.fetchall()] 35 def get_table_description(self, cursor, table_name): 36 "Returns a description of the table, with the DB-API cursor.description interface." 37 cursor.execute("SELECT * FROM %s LIMIT 1" % self.ops.quote_name(table_name)) 38 return cursor.description 15 39 16 def get_table_description(cursor, table_name): 17 "Returns a description of the table, with the DB-API cursor.description interface." 18 cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name)) 19 return cursor.description 40 def get_relations(self, cursor, table_name): 41 """ 42 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 43 representing all relationships to the given table. Indexes are 0-based. 44 """ 45 cursor.execute(""" 46 SELECT con.conkey, con.confkey, c2.relname 47 FROM pg_constraint con, pg_class c1, pg_class c2 48 WHERE c1.oid = con.conrelid 49 AND c2.oid = con.confrelid 50 AND c1.relname = %s 51 AND con.contype = 'f'""", [table_name]) 52 relations = {} 53 for row in cursor.fetchall(): 54 try: 55 # row[0] and row[1] are like "{2}", so strip the curly braces. 56 relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2]) 57 except ValueError: 58 continue 59 return relations 20 60 21 def get_relations(cursor, table_name): 22 """ 23 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 24 representing all relationships to the given table. Indexes are 0-based. 25 """ 26 cursor.execute(""" 27 SELECT con.conkey, con.confkey, c2.relname 28 FROM pg_constraint con, pg_class c1, pg_class c2 29 WHERE c1.oid = con.conrelid 30 AND c2.oid = con.confrelid 31 AND c1.relname = %s 32 AND con.contype = 'f'""", [table_name]) 33 relations = {} 34 for row in cursor.fetchall(): 35 try: 36 # row[0] and row[1] are like "{2}", so strip the curly braces. 37 relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2]) 38 except ValueError: 39 continue 40 return relations 61 def get_indexes(self, cursor, table_name): 62 """ 63 Returns a dictionary of fieldname -> infodict for the given table, 64 where each infodict is in the format: 65 {'primary_key': boolean representing whether it's the primary key, 66 'unique': boolean representing whether it's a unique index} 67 """ 68 # This query retrieves each index on the given table, including the 69 # first associated field name 70 cursor.execute(""" 71 SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary 72 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, 73 pg_catalog.pg_index idx, pg_catalog.pg_attribute attr 74 WHERE c.oid = idx.indrelid 75 AND idx.indexrelid = c2.oid 76 AND attr.attrelid = c.oid 77 AND attr.attnum = idx.indkey[0] 78 AND c.relname = %s""", [table_name]) 79 indexes = {} 80 for row in cursor.fetchall(): 81 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 82 # a string of space-separated integers. This designates the field 83 # indexes (1-based) of the fields that have indexes on the table. 84 # Here, we skip any indexes across multiple fields. 85 if ' ' in row[1]: 86 continue 87 indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]} 88 return indexes 41 89 42 def get_indexes(cursor, table_name):43 """44 Returns a dictionary of fieldname -> infodict for the given table,45 where each infodict is in the format:46 {'primary_key': boolean representing whether it's the primary key,47 'unique': boolean representing whether it's a unique index}48 """49 # This query retrieves each index on the given table, including the50 # first associated field name51 cursor.execute("""52 SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary53 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,54 pg_catalog.pg_index idx, pg_catalog.pg_attribute attr55 WHERE c.oid = idx.indrelid56 AND idx.indexrelid = c2.oid57 AND attr.attrelid = c.oid58 AND attr.attnum = idx.indkey[0]59 AND c.relname = %s""", [table_name])60 indexes = {}61 for row in cursor.fetchall():62 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as63 # a string of space-separated integers. This designates the field64 # indexes (1-based) of the fields that have indexes on the table.65 # Here, we skip any indexes across multiple fields.66 if ' ' in row[1]:67 continue68 indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}69 return indexes70 71 # Maps type codes to Django Field types.72 DATA_TYPES_REVERSE = {73 16: 'BooleanField',74 21: 'SmallIntegerField',75 23: 'IntegerField',76 25: 'TextField',77 701: 'FloatField',78 869: 'IPAddressField',79 1043: 'CharField',80 1082: 'DateField',81 1083: 'TimeField',82 1114: 'DateTimeField',83 1184: 'DateTimeField',84 1266: 'TimeField',85 1700: 'DecimalField',86 } -
django/db/backends/postgresql_psycopg2/base.py
diff -r fda9a525ebea django/db/backends/postgresql_psycopg2/base.py
a b 4 4 Requires psycopg 2: http://initd.org/projects/psycopg2 5 5 """ 6 6 7 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures 7 from django.db.backends import BaseDatabaseFeatures 8 from django.db.backends import BaseDatabaseValidation 9 from django.db.backends import BaseDatabaseWrapper 8 10 from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations 11 from django.db.backends.postgresql.client import DatabaseClient 12 from django.db.backends.postgresql.creation import DatabaseCreation 13 from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection 14 9 15 from django.utils.safestring import SafeUnicode 10 16 try: 11 17 import psycopg2 as Database … … 30 36 # http://www.initd.org/tracker/psycopg/wiki/psycopg2_documentation#postgresql-status-message-and-executed-query 31 37 return cursor.query 32 38 39 class DatabaseValidation(BaseDatabaseValidation): 40 pass 41 33 42 class DatabaseWrapper(BaseDatabaseWrapper): 34 43 features = DatabaseFeatures() 35 44 ops = DatabaseOperations() 45 client = DatabaseClient() 46 creation = DatabaseCreation(ops, features) 47 introspection = DatabaseIntrospection(ops) 48 validation = DatabaseValidation() 49 36 50 operators = { 37 51 'exact': '= %s', 38 52 'iexact': 'ILIKE %s', -
django/db/backends/postgresql_psycopg2/client.py
diff -r fda9a525ebea django/db/backends/postgresql_psycopg2/client.py
a b 1 from django.db.backends.postgresql.client import * -
django/db/backends/postgresql_psycopg2/creation.py
diff -r fda9a525ebea django/db/backends/postgresql_psycopg2/creation.py
a b 1 from django.db.backends.postgresql.creation import * -
django/db/backends/postgresql_psycopg2/introspection.py
diff -r fda9a525ebea django/db/backends/postgresql_psycopg2/introspection.py
a b 1 from django.db.backends.postgresql _psycopg2.base import DatabaseOperations1 from django.db.backends.postgresql.introspection import DatabaseIntrospection as PostgresDatabaseIntrospection 2 2 3 quote_name = DatabaseOperations().quote_name 3 class DatabaseIntrospection(PostgresDatabaseIntrospection): 4 4 5 def get_table_list(cursor): 6 "Returns a list of table names in the current database." 7 cursor.execute(""" 8 SELECT c.relname 9 FROM pg_catalog.pg_class c 10 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 11 WHERE c.relkind IN ('r', 'v', '') 12 AND n.nspname NOT IN ('pg_catalog', 'pg_toast') 13 AND pg_catalog.pg_table_is_visible(c.oid)""") 14 return [row[0] for row in cursor.fetchall()] 15 16 def get_table_description(cursor, table_name): 17 "Returns a description of the table, with the DB-API cursor.description interface." 18 cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name)) 19 return cursor.description 20 21 def get_relations(cursor, table_name): 22 """ 23 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 24 representing all relationships to the given table. Indexes are 0-based. 25 """ 26 cursor.execute(""" 27 SELECT con.conkey, con.confkey, c2.relname 28 FROM pg_constraint con, pg_class c1, pg_class c2 29 WHERE c1.oid = con.conrelid 30 AND c2.oid = con.confrelid 31 AND c1.relname = %s 32 AND con.contype = 'f'""", [table_name]) 33 relations = {} 34 for row in cursor.fetchall(): 35 # row[0] and row[1] are single-item lists, so grab the single item. 36 relations[row[0][0] - 1] = (row[1][0] - 1, row[2]) 37 return relations 38 39 def get_indexes(cursor, table_name): 40 """ 41 Returns a dictionary of fieldname -> infodict for the given table, 42 where each infodict is in the format: 43 {'primary_key': boolean representing whether it's the primary key, 44 'unique': boolean representing whether it's a unique index} 45 """ 46 # This query retrieves each index on the given table, including the 47 # first associated field name 48 cursor.execute(""" 49 SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary 50 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, 51 pg_catalog.pg_index idx, pg_catalog.pg_attribute attr 52 WHERE c.oid = idx.indrelid 53 AND idx.indexrelid = c2.oid 54 AND attr.attrelid = c.oid 55 AND attr.attnum = idx.indkey[0] 56 AND c.relname = %s""", [table_name]) 57 indexes = {} 58 for row in cursor.fetchall(): 59 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 60 # a string of space-separated integers. This designates the field 61 # indexes (1-based) of the fields that have indexes on the table. 62 # Here, we skip any indexes across multiple fields. 63 if ' ' in row[1]: 64 continue 65 indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]} 66 return indexes 67 68 # Maps type codes to Django Field types. 69 DATA_TYPES_REVERSE = { 70 16: 'BooleanField', 71 21: 'SmallIntegerField', 72 23: 'IntegerField', 73 25: 'TextField', 74 701: 'FloatField', 75 869: 'IPAddressField', 76 1043: 'CharField', 77 1082: 'DateField', 78 1083: 'TimeField', 79 1114: 'DateTimeField', 80 1184: 'DateTimeField', 81 1266: 'TimeField', 82 1700: 'DecimalField', 83 } 5 def get_relations(self, cursor, table_name): 6 """ 7 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 8 representing all relationships to the given table. Indexes are 0-based. 9 """ 10 cursor.execute(""" 11 SELECT con.conkey, con.confkey, c2.relname 12 FROM pg_constraint con, pg_class c1, pg_class c2 13 WHERE c1.oid = con.conrelid 14 AND c2.oid = con.confrelid 15 AND c1.relname = %s 16 AND con.contype = 'f'""", [table_name]) 17 relations = {} 18 for row in cursor.fetchall(): 19 # row[0] and row[1] are single-item lists, so grab the single item. 20 relations[row[0][0] - 1] = (row[1][0] - 1, row[2]) 21 return relations -
django/db/backends/sqlite3/base.py
diff -r fda9a525ebea django/db/backends/sqlite3/base.py
a b 6 6 Python 2.5 and later use the sqlite3 module in the standard library. 7 7 """ 8 8 9 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 9 from django.db.backends import BaseDatabaseWrapper 10 from django.db.backends import BaseDatabaseFeatures 11 from django.db.backends import BaseDatabaseOperations 12 from django.db.backends import BaseDatabaseValidation 13 from django.db.backends import util 14 from django.db.backends.sqlite3.client import DatabaseClient 15 from django.db.backends.sqlite3.creation import DatabaseCreation 16 from django.db.backends.sqlite3.introspection import DatabaseIntrospection 17 10 18 try: 11 19 try: 12 20 from sqlite3 import dbapi2 as Database … … 89 97 second = '%s-12-31 23:59:59.999999' 90 98 return [first % value, second % value] 91 99 100 class DatabaseValidation(BaseDatabaseValidation): 101 pass 92 102 93 103 class DatabaseWrapper(BaseDatabaseWrapper): 94 104 features = DatabaseFeatures() 95 105 ops = DatabaseOperations() 96 106 client = DatabaseClient() 107 creation = DatabaseCreation(ops, features) 108 introspection = DatabaseIntrospection(ops) 109 validation = DatabaseValidation() 110 97 111 # SQLite requires LIKE statements to include an ESCAPE clause if the value 98 112 # being escaped has a percent or underscore in it. 99 113 # See http://www.sqlite.org/lang_expr.html for an explanation. -
django/db/backends/sqlite3/client.py
diff -r fda9a525ebea django/db/backends/sqlite3/client.py
a b 1 from django.db.backends import BaseDatabaseClient 1 2 from django.conf import settings 2 3 import os 3 4 4 def runshell(): 5 args = ['', settings.DATABASE_NAME] 6 os.execvp('sqlite3', args) 5 class DatabaseClient(BaseDatabaseClient): 6 def runshell(self): 7 args = ['', settings.DATABASE_NAME] 8 os.execvp('sqlite3', args) -
django/db/backends/sqlite3/creation.py
diff -r fda9a525ebea django/db/backends/sqlite3/creation.py
a b 1 # SQLite doesn't actually support most of these types, but it "does the right 2 # thing" given more verbose field definitions, so leave them as is so that 3 # schema inspection is more useful. 4 DATA_TYPES = { 5 'AutoField': 'integer', 6 'BooleanField': 'bool', 7 'CharField': 'varchar(%(max_length)s)', 8 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 9 'DateField': 'date', 10 'DateTimeField': 'datetime', 11 'DecimalField': 'decimal', 12 'FileField': 'varchar(%(max_length)s)', 13 'FilePathField': 'varchar(%(max_length)s)', 14 'FloatField': 'real', 15 'IntegerField': 'integer', 16 'IPAddressField': 'char(15)', 17 'NullBooleanField': 'bool', 18 'OneToOneField': 'integer', 19 'PhoneNumberField': 'varchar(20)', 20 'PositiveIntegerField': 'integer unsigned', 21 'PositiveSmallIntegerField': 'smallint unsigned', 22 'SlugField': 'varchar(%(max_length)s)', 23 'SmallIntegerField': 'smallint', 24 'TextField': 'text', 25 'TimeField': 'time', 26 'USStateField': 'varchar(2)', 27 } 1 import os 2 import sys 3 from django.conf import settings 4 from django.db.backends.creation import BaseDatabaseCreation 5 6 class DatabaseCreation(BaseDatabaseCreation): 7 # SQLite doesn't actually support most of these types, but it "does the right 8 # thing" given more verbose field definitions, so leave them as is so that 9 # schema inspection is more useful. 10 data_types = { 11 'AutoField': 'integer', 12 'BooleanField': 'bool', 13 'CharField': 'varchar(%(max_length)s)', 14 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 15 'DateField': 'date', 16 'DateTimeField': 'datetime', 17 'DecimalField': 'decimal', 18 'FileField': 'varchar(%(max_length)s)', 19 'FilePathField': 'varchar(%(max_length)s)', 20 'FloatField': 'real', 21 'IntegerField': 'integer', 22 'IPAddressField': 'char(15)', 23 'NullBooleanField': 'bool', 24 'OneToOneField': 'integer', 25 'PhoneNumberField': 'varchar(20)', 26 'PositiveIntegerField': 'integer unsigned', 27 'PositiveSmallIntegerField': 'smallint unsigned', 28 'SlugField': 'varchar(%(max_length)s)', 29 'SmallIntegerField': 'smallint', 30 'TextField': 'text', 31 'TimeField': 'time', 32 'USStateField': 'varchar(2)', 33 } 34 35 def _create_test_db(self, connection, verbosity, autoclobber): 36 if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:": 37 test_database_name = settings.TEST_DATABASE_NAME 38 # Erase the old test database 39 if verbosity >= 1: 40 print "Destroying old test database..." 41 if os.access(test_database_name, os.F_OK): 42 if not autoclobber: 43 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % test_database_name) 44 if autoclobber or confirm == 'yes': 45 try: 46 if verbosity >= 1: 47 print "Destroying old test database..." 48 os.remove(test_database_name) 49 except Exception, e: 50 sys.stderr.write("Got an error deleting the old test database: %s\n" % e) 51 sys.exit(2) 52 else: 53 print "Tests cancelled." 54 sys.exit(1) 55 if verbosity >= 1: 56 print "Creating test database..." 57 else: 58 test_database_name = ":memory:" 59 return test_database_name 60 61 def _destroy_test_db(self, connection, test_database_name, verbosity): 62 if test_database_name and test_database_name != ":memory:": 63 # Remove the SQLite database file 64 os.remove(test_database_name) 65 66 No newline at end of file -
django/db/backends/sqlite3/introspection.py
diff -r fda9a525ebea django/db/backends/sqlite3/introspection.py
a b 1 from django.db.backends.sqlite3.base import DatabaseOperations 2 3 quote_name = DatabaseOperations().quote_name 4 5 def get_table_list(cursor): 6 "Returns a list of table names in the current database." 7 # Skip the sqlite_sequence system table used for autoincrement key 8 # generation. 9 cursor.execute(""" 10 SELECT name FROM sqlite_master 11 WHERE type='table' AND NOT name='sqlite_sequence' 12 ORDER BY name""") 13 return [row[0] for row in cursor.fetchall()] 14 15 def get_table_description(cursor, table_name): 16 "Returns a description of the table, with the DB-API cursor.description interface." 17 return [(info['name'], info['type'], None, None, None, None, 18 info['null_ok']) for info in _table_info(cursor, table_name)] 19 20 def get_relations(cursor, table_name): 21 raise NotImplementedError 22 23 def get_indexes(cursor, table_name): 24 """ 25 Returns a dictionary of fieldname -> infodict for the given table, 26 where each infodict is in the format: 27 {'primary_key': boolean representing whether it's the primary key, 28 'unique': boolean representing whether it's a unique index} 29 """ 30 indexes = {} 31 for info in _table_info(cursor, table_name): 32 indexes[info['name']] = {'primary_key': info['pk'] != 0, 33 'unique': False} 34 cursor.execute('PRAGMA index_list(%s)' % quote_name(table_name)) 35 # seq, name, unique 36 for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]: 37 if not unique: 38 continue 39 cursor.execute('PRAGMA index_info(%s)' % quote_name(index)) 40 info = cursor.fetchall() 41 # Skip indexes across multiple fields 42 if len(info) != 1: 43 continue 44 name = info[0][2] # seqno, cid, name 45 indexes[name]['unique'] = True 46 return indexes 47 48 def _table_info(cursor, name): 49 cursor.execute('PRAGMA table_info(%s)' % quote_name(name)) 50 # cid, name, type, notnull, dflt_value, pk 51 return [{'name': field[1], 52 'type': field[2], 53 'null_ok': not field[3], 54 'pk': field[5] # undocumented 55 } for field in cursor.fetchall()] 56 57 # Maps SQL types to Django Field types. Some of the SQL types have multiple 58 # entries here because SQLite allows for anything and doesn't normalize the 59 # field type; it uses whatever was given. 60 BASE_DATA_TYPES_REVERSE = { 61 'bool': 'BooleanField', 62 'boolean': 'BooleanField', 63 'smallint': 'SmallIntegerField', 64 'smallinteger': 'SmallIntegerField', 65 'int': 'IntegerField', 66 'integer': 'IntegerField', 67 'text': 'TextField', 68 'char': 'CharField', 69 'date': 'DateField', 70 'datetime': 'DateTimeField', 71 'time': 'TimeField', 72 } 1 from django.db.backends import BaseDatabaseIntrospection 73 2 74 3 # This light wrapper "fakes" a dictionary interface, because some SQLite data 75 4 # types include variables in them -- e.g. "varchar(30)" -- and can't be matched 76 5 # as a simple dictionary lookup. 77 6 class FlexibleFieldLookupDict: 7 # Maps SQL types to Django Field types. Some of the SQL types have multiple 8 # entries here because SQLite allows for anything and doesn't normalize the 9 # field type; it uses whatever was given. 10 base_data_types_reverse = { 11 'bool': 'BooleanField', 12 'boolean': 'BooleanField', 13 'smallint': 'SmallIntegerField', 14 'smallinteger': 'SmallIntegerField', 15 'int': 'IntegerField', 16 'integer': 'IntegerField', 17 'text': 'TextField', 18 'char': 'CharField', 19 'date': 'DateField', 20 'datetime': 'DateTimeField', 21 'time': 'TimeField', 22 } 23 78 24 def __getitem__(self, key): 79 25 key = key.lower() 80 26 try: 81 return BASE_DATA_TYPES_REVERSE[key]27 return self.base_data_types_reverse[key] 82 28 except KeyError: 83 29 import re 84 30 m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key) … … 86 32 return ('CharField', {'max_length': int(m.group(1))}) 87 33 raise KeyError 88 34 89 DATA_TYPES_REVERSE = FlexibleFieldLookupDict() 35 class DatabaseIntrospection(BaseDatabaseIntrospection): 36 data_types_reverse = FlexibleFieldLookupDict() 37 38 def __init__(self, ops): 39 self.ops = ops 40 41 def get_table_list(self, cursor): 42 "Returns a list of table names in the current database." 43 # Skip the sqlite_sequence system table used for autoincrement key 44 # generation. 45 cursor.execute(""" 46 SELECT name FROM sqlite_master 47 WHERE type='table' AND NOT name='sqlite_sequence' 48 ORDER BY name""") 49 return [row[0] for row in cursor.fetchall()] 50 51 def get_table_description(self, cursor, table_name): 52 "Returns a description of the table, with the DB-API cursor.description interface." 53 return [(info['name'], info['type'], None, None, None, None, 54 info['null_ok']) for info in self._table_info(cursor, table_name)] 55 56 def get_relations(self, cursor, table_name): 57 raise NotImplementedError 58 59 def get_indexes(self, cursor, table_name): 60 """ 61 Returns a dictionary of fieldname -> infodict for the given table, 62 where each infodict is in the format: 63 {'primary_key': boolean representing whether it's the primary key, 64 'unique': boolean representing whether it's a unique index} 65 """ 66 indexes = {} 67 for info in self._table_info(cursor, table_name): 68 indexes[info['name']] = {'primary_key': info['pk'] != 0, 69 'unique': False} 70 cursor.execute('PRAGMA index_list(%s)' % self.ops.quote_name(table_name)) 71 # seq, name, unique 72 for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]: 73 if not unique: 74 continue 75 cursor.execute('PRAGMA index_info(%s)' % self.ops.quote_name(index)) 76 info = cursor.fetchall() 77 # Skip indexes across multiple fields 78 if len(info) != 1: 79 continue 80 name = info[0][2] # seqno, cid, name 81 indexes[name]['unique'] = True 82 return indexes 83 84 def _table_info(self, cursor, name): 85 cursor.execute('PRAGMA table_info(%s)' % self.ops.quote_name(name)) 86 # cid, name, type, notnull, dflt_value, pk 87 return [{'name': field[1], 88 'type': field[2], 89 'null_ok': not field[3], 90 'pk': field[5] # undocumented 91 } for field in cursor.fetchall()] 92 -
django/db/models/fields/__init__.py
diff -r fda9a525ebea django/db/models/fields/__init__.py
a b 7 7 except ImportError: 8 8 from django.utils import _decimal as decimal # for Python 2.3 9 9 10 from django.db import connection , get_creation_module10 from django.db import connection 11 11 from django.db.models import signals 12 12 from django.db.models.query_utils import QueryWrapper 13 13 from django.dispatch import dispatcher … … 145 145 # as the TextField Django field type, which means XMLField's 146 146 # get_internal_type() returns 'TextField'. 147 147 # 148 # But the limitation of the get_internal_type() / DATA_TYPESapproach148 # But the limitation of the get_internal_type() / data_types approach 149 149 # is that it cannot handle database column types that aren't already 150 150 # mapped to one of the built-in Django field types. In this case, you 151 151 # can implement db_type() instead of get_internal_type() to specify 152 152 # exactly which wacky database column type you want to use. 153 153 data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_") 154 154 try: 155 return get_creation_module().DATA_TYPES[self.get_internal_type()] % data155 return connection.creation.data_types[self.get_internal_type()] % data 156 156 except KeyError: 157 157 return None 158 158 -
django/test/simple.py
diff -r fda9a525ebea django/test/simple.py
a b 3 3 from django.db.models import get_app, get_apps 4 4 from django.test import _doctest as doctest 5 5 from django.test.utils import setup_test_environment, teardown_test_environment 6 from django.test.utils import create_test_db, destroy_test_db7 6 from django.test.testcases import OutputChecker, DocTestRunner 8 7 9 8 # The module name for tests outside models.py … … 139 138 suite.addTest(test) 140 139 141 140 old_name = settings.DATABASE_NAME 142 create_test_db(verbosity, autoclobber=not interactive) 141 from django.db import connection 142 connection.creation.create_test_db(verbosity, autoclobber=not interactive) 143 143 result = unittest.TextTestRunner(verbosity=verbosity).run(suite) 144 destroy_test_db(old_name, verbosity)144 connection.creation.destroy_test_db(old_name, verbosity) 145 145 146 146 teardown_test_environment() 147 147 -
django/test/utils.py
diff -r fda9a525ebea django/test/utils.py
a b 1 1 import sys, time, os 2 2 from django.conf import settings 3 from django.db import connection , get_creation_module3 from django.db import connection 4 4 from django.core import mail 5 from django.core.management import call_command6 5 from django.dispatch import dispatcher 7 6 from django.test import signals 8 7 from django.template import Template 9 8 from django.utils.translation import deactivate 10 11 # The prefix to put on the default database name when creating12 # the test database.13 TEST_DATABASE_PREFIX = 'test_'14 9 15 10 def instrumented_test_render(self, context): 16 11 """ … … 71 66 72 67 del mail.outbox 73 68 74 def _set_autocommit(connection):75 "Make sure a connection is in autocommit mode."76 if hasattr(connection.connection, "autocommit"):77 if callable(connection.connection.autocommit):78 connection.connection.autocommit(True)79 else:80 connection.connection.autocommit = True81 elif hasattr(connection.connection, "set_isolation_level"):82 connection.connection.set_isolation_level(0)83 84 def get_mysql_create_suffix():85 suffix = []86 if settings.TEST_DATABASE_CHARSET:87 suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET)88 if settings.TEST_DATABASE_COLLATION:89 suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION)90 return ' '.join(suffix)91 92 def get_postgresql_create_suffix():93 assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time."94 if settings.TEST_DATABASE_CHARSET:95 return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET96 return ''97 98 def create_test_db(verbosity=1, autoclobber=False):99 """100 Creates a test database, prompting the user for confirmation if the101 database already exists. Returns the name of the test database created.102 """103 # If the database backend wants to create the test DB itself, let it104 creation_module = get_creation_module()105 if hasattr(creation_module, "create_test_db"):106 creation_module.create_test_db(settings, connection, verbosity, autoclobber)107 return108 109 if verbosity >= 1:110 print "Creating test database..."111 # If we're using SQLite, it's more convenient to test against an112 # in-memory database. Using the TEST_DATABASE_NAME setting you can still choose113 # to run on a physical database.114 if settings.DATABASE_ENGINE == "sqlite3":115 if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:":116 TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME117 # Erase the old test database118 if verbosity >= 1:119 print "Destroying old test database..."120 if os.access(TEST_DATABASE_NAME, os.F_OK):121 if not autoclobber:122 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)123 if autoclobber or confirm == 'yes':124 try:125 if verbosity >= 1:126 print "Destroying old test database..."127 os.remove(TEST_DATABASE_NAME)128 except Exception, e:129 sys.stderr.write("Got an error deleting the old test database: %s\n" % e)130 sys.exit(2)131 else:132 print "Tests cancelled."133 sys.exit(1)134 if verbosity >= 1:135 print "Creating test database..."136 else:137 TEST_DATABASE_NAME = ":memory:"138 else:139 suffix = {140 'postgresql': get_postgresql_create_suffix,141 'postgresql_psycopg2': get_postgresql_create_suffix,142 'mysql': get_mysql_create_suffix,143 }.get(settings.DATABASE_ENGINE, lambda: '')()144 if settings.TEST_DATABASE_NAME:145 TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME146 else:147 TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME148 149 qn = connection.ops.quote_name150 151 # Create the test database and connect to it. We need to autocommit152 # if the database supports it because PostgreSQL doesn't allow153 # CREATE/DROP DATABASE statements within transactions.154 cursor = connection.cursor()155 _set_autocommit(connection)156 try:157 cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))158 except Exception, e:159 sys.stderr.write("Got an error creating the test database: %s\n" % e)160 if not autoclobber:161 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)162 if autoclobber or confirm == 'yes':163 try:164 if verbosity >= 1:165 print "Destroying old test database..."166 cursor.execute("DROP DATABASE %s" % qn(TEST_DATABASE_NAME))167 if verbosity >= 1:168 print "Creating test database..."169 cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))170 except Exception, e:171 sys.stderr.write("Got an error recreating the test database: %s\n" % e)172 sys.exit(2)173 else:174 print "Tests cancelled."175 sys.exit(1)176 177 connection.close()178 settings.DATABASE_NAME = TEST_DATABASE_NAME179 180 call_command('syncdb', verbosity=verbosity, interactive=False)181 182 if settings.CACHE_BACKEND.startswith('db://'):183 cache_name = settings.CACHE_BACKEND[len('db://'):]184 call_command('createcachetable', cache_name)185 186 # Get a cursor (even though we don't need one yet). This has187 # the side effect of initializing the test database.188 cursor = connection.cursor()189 190 return TEST_DATABASE_NAME191 192 def destroy_test_db(old_database_name, verbosity=1):193 # If the database wants to drop the test DB itself, let it194 creation_module = get_creation_module()195 if hasattr(creation_module, "destroy_test_db"):196 creation_module.destroy_test_db(settings, connection, old_database_name, verbosity)197 return198 199 if verbosity >= 1:200 print "Destroying test database..."201 connection.close()202 TEST_DATABASE_NAME = settings.DATABASE_NAME203 settings.DATABASE_NAME = old_database_name204 if settings.DATABASE_ENGINE == "sqlite3":205 if TEST_DATABASE_NAME and TEST_DATABASE_NAME != ":memory:":206 # Remove the SQLite database file207 os.remove(TEST_DATABASE_NAME)208 else:209 # Remove the test database to clean up after210 # ourselves. Connect to the previous database (not the test database)211 # to do so, because it's not allowed to delete a database while being212 # connected to it.213 cursor = connection.cursor()214 _set_autocommit(connection)215 time.sleep(1) # To avoid "database is being accessed by other users" errors.216 cursor.execute("DROP DATABASE %s" % connection.ops.quote_name(TEST_DATABASE_NAME))217 connection.close() -
docs/testing.txt
diff -r fda9a525ebea docs/testing.txt
a b 1026 1026 black magic hooks into the template system and restoring normal e-mail 1027 1027 services. 1028 1028 1029 The creation module of the database backend (``connection.creation``) also 1030 provides some utilities that can be useful during testing. 1031 1029 1032 ``create_test_db(verbosity=1, autoclobber=False)`` 1030 1033 Creates a new test database and runs ``syncdb`` against it. 1031 1034