Ticket #5461: 5461.patch
| File 5461.patch, 86.3 kB (added by brantley, 1 year ago) |
|---|
-
test/utils.py
old new 1 1 import sys, time 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 5 from django.core.management import call_command 6 6 from django.dispatch import dispatcher … … 95 95 database already exists. Returns the name of the test database created. 96 96 """ 97 97 # If the database backend wants to create the test DB itself, let it 98 creation_module = get_creation_module() 99 if hasattr(creation_module, "create_test_db"): 100 creation_module.create_test_db(settings, connection, verbosity, autoclobber) 98 if hasattr(connection.creation, "create_test_db"): 99 connection.creation.create_test_db(settings, connection, verbosity, autoclobber) 101 100 return 102 101 103 102 if verbosity >= 1: … … 163 162 164 163 def destroy_test_db(old_database_name, verbosity=1): 165 164 # If the database wants to drop the test DB itself, let it 166 creation_module = get_creation_module() 167 if hasattr(creation_module, "destroy_test_db"): 168 creation_module.destroy_test_db(settings, connection, old_database_name, verbosity) 165 if hasattr(connection.creation, "destroy_test_db"): 166 connection.creation.destroy_test_db(settings, connection, old_database_name, verbosity) 169 167 return 170 168 171 169 # Unless we're using SQLite, remove the test database to clean up after -
db/models/fields/__init__.py
old new 6 6 except ImportError: 7 7 from django.utils import _decimal as decimal # for Python 2.3 8 8 9 from django.db import get_creation_module10 9 from django.db.models import signals 11 10 from django.dispatch import dispatcher 12 11 from django.conf import settings … … 145 144 # mapped to one of the built-in Django field types. In this case, you 146 145 # can implement db_type() instead of get_internal_type() to specify 147 146 # exactly which wacky database column type you want to use. 148 data_types = get_creation_module().DATA_TYPES 147 from django.db import connection 148 data_types = connection.creation.data_types 149 149 internal_type = self.get_internal_type() 150 150 return data_types[internal_type] % self.__dict__ 151 151 -
db/__init__.py
old new 23 23 else: 24 24 raise # If there's some other error, this must be an error in Django itself. 25 25 26 get_introspection_module = lambda: __import__('django.db.backends.%s.introspection' % settings.DATABASE_ENGINE, {}, {}, [''])27 get_creation_module = lambda: __import__('django.db.backends.%s.creation' % settings.DATABASE_ENGINE, {}, {}, [''])28 26 runshell = lambda: __import__('django.db.backends.%s.client' % settings.DATABASE_ENGINE, {}, {}, ['']).runshell() 29 27 30 28 connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS) … … 46 44 def _rollback_on_exception(): 47 45 from django.db import transaction 48 46 transaction.rollback_unless_managed() 49 dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception) 47 dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception) -
db/backends/ado_mssql/introspection.py
old new 1 def get_table_list(cursor): 2 raise NotImplementedError 1 from django.db.backends.introspection import BaseIntrospection 3 2 4 def get_table_description(cursor, table_name): 5 raise NotImplementedError 6 7 def get_relations(cursor, table_name): 8 raise NotImplementedError 9 10 def get_indexes(cursor, table_name): 11 raise NotImplementedError 12 13 DATA_TYPES_REVERSE = {} 3 class Introspection(BaseIntrospection): 4 pass 5 -
db/backends/ado_mssql/creation.py
old new 1 DATA_TYPES = { 2 'AutoField': 'int IDENTITY (1, 1)', 3 'BooleanField': 'bit', 4 'CharField': 'varchar(%(max_length)s)', 5 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 6 'DateField': 'smalldatetime', 7 'DateTimeField': 'smalldatetime', 8 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 9 'FileField': 'varchar(100)', 10 'FilePathField': 'varchar(100)', 11 'FloatField': 'double precision', 12 'ImageField': 'varchar(100)', 13 'IntegerField': 'int', 14 'IPAddressField': 'char(15)', 15 'NullBooleanField': 'bit', 16 'OneToOneField': 'int', 17 'PhoneNumberField': 'varchar(20)', 18 'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)', 19 'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)', 20 'SlugField': 'varchar(%(max_length)s)', 21 'SmallIntegerField': 'smallint', 22 'TextField': 'text', 23 'TimeField': 'time', 24 'USStateField': 'varchar(2)', 25 } 1 from django.db.backends.creation import BaseCreation 2 3 class Creation(BaseCreation): 4 data_types = { 5 'AutoField': 'int IDENTITY (1, 1)', 6 'BooleanField': 'bit', 7 'CharField': 'varchar(%(max_length)s)', 8 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 9 'DateField': 'smalldatetime', 10 'DateTimeField': 'smalldatetime', 11 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 12 'FileField': 'varchar(100)', 13 'FilePathField': 'varchar(100)', 14 'FloatField': 'double precision', 15 'ImageField': 'varchar(100)', 16 'IntegerField': 'int', 17 'IPAddressField': 'char(15)', 18 'NullBooleanField': 'bit', 19 'OneToOneField': 'int', 20 'PhoneNumberField': 'varchar(20)', 21 'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)', 22 'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)', 23 'SlugField': 'varchar(%(max_length)s)', 24 'SmallIntegerField': 'smallint', 25 'TextField': 'text', 26 'TimeField': 'time', 27 'USStateField': 'varchar(2)', 28 } -
db/backends/mysql_old/introspection.py
old new 1 from django.db.backends.introspection import BaseIntrospection 1 2 from django.db.backends.mysql_old.base import DatabaseOperations 2 3 from MySQLdb import ProgrammingError, OperationalError 3 4 from MySQLdb.constants import FIELD_TYPE … … 6 7 quote_name = DatabaseOperations().quote_name 7 8 foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 8 9 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()] 10 class Introspection(BaseIntrospection): 11 data_types_reverse = { 12 FIELD_TYPE.BLOB: 'TextField', 13 FIELD_TYPE.CHAR: 'CharField', 14 FIELD_TYPE.DECIMAL: 'DecimalField', 15 FIELD_TYPE.DATE: 'DateField', 16 FIELD_TYPE.DATETIME: 'DateTimeField', 17 FIELD_TYPE.DOUBLE: 'FloatField', 18 FIELD_TYPE.FLOAT: 'FloatField', 19 FIELD_TYPE.INT24: 'IntegerField', 20 FIELD_TYPE.LONG: 'IntegerField', 21 FIELD_TYPE.LONGLONG: 'IntegerField', 22 FIELD_TYPE.SHORT: 'IntegerField', 23 FIELD_TYPE.STRING: 'TextField', 24 FIELD_TYPE.TIMESTAMP: 'DateTimeField', 25 FIELD_TYPE.TINY: 'IntegerField', 26 FIELD_TYPE.TINY_BLOB: 'TextField', 27 FIELD_TYPE.MEDIUM_BLOB: 'TextField', 28 FIELD_TYPE.LONG_BLOB: 'TextField', 29 FIELD_TYPE.VAR_STRING: 'CharField', 30 } 13 31 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.description32 def get_table_list(self, cursor): 33 "Returns a list of table names in the current database." 34 cursor.execute("SHOW TABLES") 35 return [row[0] for row in cursor.fetchall()] 18 36 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))]) 37 def get_table_description(self, cursor, table_name): 38 "Returns a description of the table, with the DB-API cursor.description interface." 39 cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name)) 40 return cursor.description 25 41 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)) 48 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()) 42 def _name_to_index(self, cursor, table_name): 43 """ 44 Returns a dictionary of {field_name: field_index} for the given table. 45 Indexes are 0-based. 46 """ 47 return dict([(d[0], i) for i, d in enumerate(self.get_table_description(cursor, table_name))]) 56 48 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) 49 def get_relations(self, cursor, table_name): 50 """ 51 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 52 representing all relationships to the given table. Indexes are 0-based. 53 """ 54 my_field_dict = self._name_to_index(cursor, table_name) 55 constraints = [] 56 relations = {} 57 try: 58 # This should work for MySQL 5.0. 59 cursor.execute(""" 60 SELECT column_name, referenced_table_name, referenced_column_name 61 FROM information_schema.key_column_usage 62 WHERE table_name = %s 63 AND table_schema = DATABASE() 64 AND referenced_table_name IS NOT NULL 65 AND referenced_column_name IS NOT NULL""", [table_name]) 66 constraints.extend(cursor.fetchall()) 67 except (ProgrammingError, OperationalError): 68 # Fall back to "SHOW CREATE TABLE", for previous MySQL versions. 69 # Go through all constraints and save the equal matches. 70 cursor.execute("SHOW CREATE TABLE %s" % quote_name(table_name)) 71 for row in cursor.fetchall(): 72 pos = 0 73 while True: 74 match = foreign_key_re.search(row[1], pos) 75 if match == None: 76 break 77 pos = match.end() 78 constraints.append(match.groups()) 61 79 62 return relations 80 for my_fieldname, other_table, other_field in constraints: 81 other_field_index = self._name_to_index(cursor, other_table)[other_field] 82 my_field_index = my_field_dict[my_fieldname] 83 relations[my_field_index] = (other_field_index, other_table) 63 84 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 indexes 85 return relations 76 86 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: 'TextField', 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 } 87 def get_indexes(self, cursor, table_name): 88 """ 89 Returns a dictionary of fieldname -> infodict for the given table, 90 where each infodict is in the format: 91 {'primary_key': boolean representing whether it's the primary key, 92 'unique': boolean representing whether it's a unique index} 93 """ 94 cursor.execute("SHOW INDEX FROM %s" % quote_name(table_name)) 95 indexes = {} 96 for row in cursor.fetchall(): 97 indexes[row[4]] = {'primary_key': (row[2] == 'PRIMARY'), 'unique': not bool(row[1])} 98 return indexes 99 -
db/backends/mysql_old/creation.py
old new 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(100)', 14 'FilePathField': 'varchar(100)', 15 'FloatField': 'double precision', 16 'ImageField': 'varchar(100)', 17 'IntegerField': 'integer', 18 'IPAddressField': 'char(15)', 19 'NullBooleanField': 'bool', 20 'OneToOneField': 'integer', 21 'PhoneNumberField': 'varchar(20)', 22 'PositiveIntegerField': 'integer UNSIGNED', 23 'PositiveSmallIntegerField': 'smallint UNSIGNED', 24 'SlugField': 'varchar(%(max_length)s)', 25 'SmallIntegerField': 'smallint', 26 'TextField': 'longtext', 27 'TimeField': 'time', 28 'USStateField': 'varchar(2)', 29 } 1 from django.db.backends.creation import BaseCreation 2 3 class Creation(BaseCreation): 4 # This dictionary maps Field objects to their associated MySQL 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 data_types = { 9 'AutoField': 'integer AUTO_INCREMENT', 10 'BooleanField': 'bool', 11 'CharField': 'varchar(%(max_length)s)', 12 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 13 'DateField': 'date', 14 'DateTimeField': 'datetime', 15 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 16 'FileField': 'varchar(100)', 17 'FilePathField': 'varchar(100)', 18 'FloatField': 'double precision', 19 'ImageField': 'varchar(100)', 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 } -
db/backends/postgresql/introspection.py
old new 1 from django.db.backends.introspection import BaseIntrospection 1 2 from django.db.backends.postgresql.base import DatabaseOperations 2 3 3 4 quote_name = DatabaseOperations().quote_name … … 2 3 3 def get_table_list(cursor): 4 "Returns a list of table names in the current database." 5 cursor.execute(""" 6 SELECT c.relname 7 FROM pg_catalog.pg_class c 8 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 9 WHERE c.relkind IN ('r', 'v', '') 10 AND n.nspname NOT IN ('pg_catalog', 'pg_toast') 11 AND pg_catalog.pg_table_is_visible(c.oid)""") 12 return [row[0] for row in cursor.fetchall()] 4 class Introspection(BaseIntrospection): 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 } 13 20 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 21 def get_table_list(self, cursor): 22 "Returns a list of table names in the current database." 23 cursor.execute(""" 24 SELECT c.relname 25 FROM pg_catalog.pg_class c 26 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 27 WHERE c.relkind IN ('r', 'v', '') 28 AND n.nspname NOT IN ('pg_catalog', 'pg_toast') 29 AND pg_catalog.pg_table_is_visible(c.oid)""") 30 return [row[0] for row in cursor.fetchall()] 18 31 19 def get_relations(cursor, table_name): 20 """ 21 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 22 representing all relationships to the given table. Indexes are 0-based. 23 """ 24 cursor.execute(""" 25 SELECT con.conkey, con.confkey, c2.relname 26 FROM pg_constraint con, pg_class c1, pg_class c2 27 WHERE c1.oid = con.conrelid 28 AND c2.oid = con.confrelid 29 AND c1.relname = %s 30 AND con.contype = 'f'""", [table_name]) 31 relations = {} 32 for row in cursor.fetchall(): 33 try: 34 # row[0] and row[1] are like "{2}", so strip the curly braces. 35 relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2]) 36 except ValueError: 37 continue 38 return relations 32 def get_table_description(self, cursor, table_name): 33 "Returns a description of the table, with the DB-API cursor.description interface." 34 cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name)) 35 return cursor.description 39 36 40 def get_indexes(cursor, table_name): 41 """ 42 Returns a dictionary of fieldname -> infodict for the given table, 43 where each infodict is in the format: 44 {'primary_key': boolean representing whether it's the primary key, 45 'unique': boolean representing whether it's a unique index} 46 """ 47 # This query retrieves each index on the given table, including the 48 # first associated field name 49 cursor.execute(""" 50 SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary 51 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, 52 pg_catalog.pg_index idx, pg_catalog.pg_attribute attr 53 WHERE c.oid = idx.indrelid 54 AND idx.indexrelid = c2.oid 55 AND attr.attrelid = c.oid 56 AND attr.attnum = idx.indkey[0] 57 AND c.relname = %s""", [table_name]) 58 indexes = {} 59 for row in cursor.fetchall(): 60 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 61 # a string of space-separated integers. This designates the field 62 # indexes (1-based) of the fields that have indexes on the table. 63 # Here, we skip any indexes across multiple fields. 64 if ' ' in row[1]: 65 continue 66 indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]} 67 return indexes 37 def get_relations(self, cursor, table_name): 38 """ 39 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 40 representing all relationships to the given table. Indexes are 0-based. 41 """ 42 cursor.execute(""" 43 SELECT con.conkey, con.confkey, c2.relname 44 FROM pg_constraint con, pg_class c1, pg_class c2 45 WHERE c1.oid = con.conrelid 46 AND c2.oid = con.confrelid 47 AND c1.relname = %s 48 AND con.contype = 'f'""", [table_name]) 49 relations = {} 50 for row in cursor.fetchall(): 51 try: 52 # row[0] and row[1] are like "{2}", so strip the curly braces. 53 relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2]) 54 except ValueError: 55 continue 56 return relations 68 57 69 # Maps type codes to Django Field types. 70 DATA_TYPES_REVERSE = { 71 16: 'BooleanField', 72 21: 'SmallIntegerField', 73 23: 'IntegerField', 74 25: 'TextField', 75 701: 'FloatField', 76 869: 'IPAddressField', 77 1043: 'CharField', 78 1082: 'DateField', 79 1083: 'TimeField', 80 1114: 'DateTimeField', 81 1184: 'DateTimeField', 82 1266: 'TimeField', 83 1700: 'DecimalField', 84 } 58 def get_indexes(self, cursor, table_name): 59 """ 60 Returns a dictionary of fieldname -> infodict for the given table, 61 where each infodict is in the format: 62 {'primary_key': boolean representing whether it's the primary key, 63 'unique': boolean representing whether it's a unique index} 64 """ 65 # This query retrieves each index on the given table, including the 66 # first associated field name 67 cursor.execute(""" 68 SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary 69 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, 70 pg_catalog.pg_index idx, pg_catalog.pg_attribute attr 71 WHERE c.oid = idx.indrelid 72 AND idx.indexrelid = c2.oid 73 AND attr.attrelid = c.oid 74 AND attr.attnum = idx.indkey[0] 75 AND c.relname = %s""", [table_name]) 76 indexes = {} 77 for row in cursor.fetchall(): 78 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 79 # a string of space-separated integers. This designates the field 80 # indexes (1-based) of the fields that have indexes on the table. 81 # Here, we skip any indexes across multiple fields. 82 if ' ' in row[1]: 83 continue 84 indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]} 85 return indexes -
db/backends/postgresql/creation.py
old new 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(100)', 14 'FilePathField': 'varchar(100)', 15 'FloatField': 'double precision', 16 'ImageField': 'varchar(100)', 17 'IntegerField': 'integer', 18 'IPAddressField': 'inet', 19 'NullBooleanField': 'boolean', 20 'OneToOneField': 'integer', 21 'PhoneNumberField': 'varchar(20)', 22 'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)', 23 'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)', 24 'SlugField': 'varchar(%(max_length)s)', 25 'SmallIntegerField': 'smallint', 26 'TextField': 'text', 27 'TimeField': 'time', 28 'USStateField': 'varchar(2)', 29 } 1 from django.db.backends.creation import BaseCreation 2 3 class Creation(BaseCreation): 4 # This dictionary maps Field objects to their associated PostgreSQL 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 data_types = { 9 'AutoField': 'serial', 10 'BooleanField': 'boolean', 11 'CharField': 'varchar(%(max_length)s)', 12 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 13 'DateField': 'date', 14 'DateTimeField': 'timestamp with time zone', 15 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 16 'FileField': 'varchar(100)', 17 'FilePathField': 'varchar(100)', 18 'FloatField': 'double precision', 19 'ImageField': 'varchar(100)', 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 } -
db/backends/sqlite3/introspection.py
old new 1 from django.db.backends.introspection import BaseIntrospection 1 2 from django.db.backends.sqlite3.base import DatabaseOperations 2 3 3 4 quote_name = DatabaseOperations().quote_name … … 2 3 3 def get_table_list(cursor):4 "Returns a list of table names in the current database."5 # Skip the sqlite_sequence system table used for autoincrement key6 # generation.7 cursor.execute("""8 SELECT name FROM sqlite_master9 WHERE type='table' AND NOT name='sqlite_sequence'10 ORDER BY name""")11 return [row[0] for row in cursor.fetchall()]12 13 def get_table_description(cursor, table_name):14 "Returns a description of the table, with the DB-API cursor.description interface."15 return [(info['name'], info['type'], None, None, None, None,16 info['null_ok']) for info in _table_info(cursor, table_name)]17 18 def get_relations(cursor, table_name):19 raise NotImplementedError20 21 def get_indexes(cursor, table_name):22 """23 Returns a dictionary of fieldname -> infodict for the given table,24 where each infodict is in the format:25 {'primary_key': boolean representing whether it's the primary key,26 'unique': boolean representing whether it's a unique index}27 """28 indexes = {}29 for info in _table_info(cursor, table_name):30 indexes[info['name']] = {'primary_key': info['pk'] != 0,31 'unique': False}32 cursor.execute('PRAGMA index_list(%s)' % quote_name(table_name))33 # seq, name, unique34 for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]:35 if not unique:36 continue37 cursor.execute('PRAGMA index_info(%s)' % quote_name(index))38 info = cursor.fetchall()39 # Skip indexes across multiple fields40 if len(info) != 1:41 continue42 name = info[0][2] # seqno, cid, name43 indexes[name]['unique'] = True44 return indexes45 46 def _table_info(cursor, name):47 cursor.execute('PRAGMA table_info(%s)' % quote_name(name))48 # cid, name, type, notnull, dflt_value, pk49 return [{'name': field[1],50 'type': field[2],51 'null_ok': not field[3],52 'pk': field[5] # undocumented53 } for field in cursor.fetchall()]54 55 # Maps SQL types to Django Field types. Some of the SQL types have multiple56 # entries here because SQLite allows for anything and doesn't normalize the57 # field type; it uses whatever was given.58 BASE_DATA_TYPES_REVERSE = {59 'bool': 'BooleanField',60 'boolean': 'BooleanField',61 'smallint': 'SmallIntegerField',62 'smallinteger': 'SmallIntegerField',63 'int': 'IntegerField',64 'integer': 'IntegerField',65 'text': 'TextField',66 'char': 'CharField',67 'date': 'DateField',68 'datetime': 'DateTimeField',69 'time': 'TimeField',70 }71 72 4 # This light wrapper "fakes" a dictionary interface, because some SQLite data 73 5 # types include variables in them -- e.g. "varchar(30)" -- and can't be matched 74 6 # as a simple dictionary lookup. 75 7 class FlexibleFieldLookupDict: 8 base_data_types_reverse = { 9 'bool': 'BooleanField', 10 'boolean': 'BooleanField', 11 'smallint': 'SmallIntegerField', 12 'smallinteger': 'SmallIntegerField', 13 'int': 'IntegerField', 14 'integer': 'IntegerField', 15 'text': 'TextField', 16 'char': 'CharField', 17 'date': 'DateField', 18 'datetime': 'DateTimeField', 19 'time': 'TimeField', 20 } 21 76 22 def __getitem__(self, key): 77 23 key = key.lower() 78 24 try: 79 return BASE_DATA_TYPES_REVERSE[key]25 return self.base_data_types_reverse[key] 80 26 except KeyError: … … 86 32 return ('CharField', {'max_length': int(m.group(1))}) 87 33 raise KeyError 88 34 89 DATA_TYPES_REVERSE = FlexibleFieldLookupDict() 35 class Introspection(BaseIntrospection): 36 # Maps SQL types to Django Field types. Some of the SQL types have multiple 37 # entries here because SQLite allows for anything and doesn't normalize the 38 # field type; it uses whatever was given. 39 data_types_reverse = FlexibleFieldLookupDict() 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)' % 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)' % 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)' % 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()] -
db/backends/sqlite3/creation.py
old new 1 1 # SQLite doesn't actually support most of these types, but it "does the right 2 2 # thing" given more verbose field definitions, so leave them as is so that 3 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(100)', 13 'FilePathField': 'varchar(100)', 14 'FloatField': 'real', 15 'ImageField': 'varchar(100)', 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': 'text', 26 'TimeField': 'time', 27 'USStateField': 'varchar(2)', 28 } 4 from django.db.backends.creation import BaseCreation 5 6 class Creation(BaseCreation): 7 data_types = { 8 'AutoField': 'integer', 9 'BooleanField': 'bool', 10 'CharField': 'varchar(%(max_length)s)', 11 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 12 'DateField': 'date', 13 'DateTimeField': 'datetime', 14 'DecimalField': 'decimal', 15 'FileField': 'varchar(100)', 16 'FilePathField': 'varchar(100)', 17 'FloatField': 'real', 18 'ImageField': 'varchar(100)', 19 'IntegerField': 'integer', 20 'IPAddressField': 'char(15)', 21 'NullBooleanField': 'bool', 22 'OneToOneField': 'integer', 23 'PhoneNumberField': 'varchar(20)', 24 'PositiveIntegerField': 'integer unsigned', 25 'PositiveSmallIntegerField': 'smallint unsigned', 26 'SlugField': 'varchar(%(max_length)s)', 27 'SmallIntegerField': 'smallint', 28 'TextField': 'text', 29 'TimeField': 'time', 30 'USStateField': 'varchar(2)', 31 } -
db/backends/mysql/introspection.py
old new 1 from django.db.backends.introspection import BaseIntrospection 1 2 from django.db.backends.mysql.base import DatabaseOperations 2 3 from MySQLdb import ProgrammingError, OperationalError 3 4 from MySQLdb.constants import FIELD_TYPE … … 6 7 quote_name = DatabaseOperations().quote_name 7 8 foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 8 9 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()] 10 class Introspection(BaseIntrospection): 11 data_types_reverse = { 12 FIELD_TYPE.BLOB: 'TextField', 13 FIELD_TYPE.CHAR: 'CharField', 14 FIELD_TYPE.DECIMAL: 'DecimalField', 15 FIELD_TYPE.DATE: 'DateField', 16 FIELD_TYPE.DATETIME: 'DateTimeField', 17 FIELD_TYPE.DOUBLE: 'FloatField', 18 FIELD_TYPE.FLOAT: 'FloatField', 19 FIELD_TYPE.INT24: 'IntegerField', 20 FIELD_TYPE.LONG: 'IntegerField', 21 FIELD_TYPE.LONGLONG: 'IntegerField', 22 FIELD_TYPE.SHORT: 'IntegerField', 23 FIELD_TYPE.STRING: 'CharField', 24 FIELD_TYPE.TIMESTAMP: 'DateTimeField', 25 FIELD_TYPE.TINY: 'IntegerField', 26 FIELD_TYPE.TINY_BLOB: 'TextField', 27 FIELD_TYPE.MEDIUM_BLOB: 'TextField', 28 FIELD_TYPE.LONG_BLOB: 'TextField', 29 FIELD_TYPE.VAR_STRING: 'CharField', 30 } 13 31 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.description32 def get_table_list(self, cursor): 33 "Returns a list of table names in the current database." 34 cursor.execute("SHOW TABLES") 35 return [row[0] for row in cursor.fetchall()] 18 36 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))]) 37 def get_table_description(self, cursor, table_name): 38 "Returns a description of the table, with the DB-API cursor.description interface." 39 cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name)) 40 return cursor.description 25 41 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)) 48 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()) 42 def _name_to_index(self, cursor, table_name): 43 """ 44 Returns a dictionary of {field_name: field_index} for the given table. 45 Indexes are 0-based. 46 """ 47 return dict([(d[0], i) for i, d in enumerate(self.get_table_description(cursor, table_name))]) 56 48 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) 49 def get_relations(self, cursor, table_name): 50 """ 51 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 52 representing all relationships to the given table. Indexes are 0-based. 53 """ 54 my_field_dict = self._name_to_index(cursor, table_name) 55 constraints = [] 56 relations = {} 57 try: 58 # This should work for MySQL 5.0. 59 cursor.execute(""" 60 SELECT column_name, referenced_table_name, referenced_column_name 61 &nb
