Django

Code

Ticket #5461: 5461.patch

File 5461.patch, 86.3 kB (added by brantley, 1 year ago)
  • test/utils.py

    old new  
    11import sys, time 
    22from django.conf import settings 
    3 from django.db import connection, get_creation_module 
     3from django.db import connection 
    44from django.core import mail 
    55from django.core.management import call_command 
    66from django.dispatch import dispatcher 
     
    9595    database already exists. Returns the name of the test database created. 
    9696    """ 
    9797    # 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) 
    101100        return 
    102101 
    103102    if verbosity >= 1: 
     
    163162 
    164163def destroy_test_db(old_database_name, verbosity=1): 
    165164    # 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) 
    169167        return 
    170168 
    171169    # Unless we're using SQLite, remove the test database to clean up after 
  • db/models/fields/__init__.py

    old new  
    66except ImportError: 
    77    from django.utils import _decimal as decimal    # for Python 2.3 
    88 
    9 from django.db import get_creation_module 
    109from django.db.models import signals 
    1110from django.dispatch import dispatcher 
    1211from django.conf import settings 
     
    145144        # mapped to one of the built-in Django field types. In this case, you 
    146145        # can implement db_type() instead of get_internal_type() to specify 
    147146        # 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 
    149149        internal_type = self.get_internal_type() 
    150150        return data_types[internal_type] % self.__dict__ 
    151151 
  • db/__init__.py

    old new  
    2323    else: 
    2424        raise # If there's some other error, this must be an error in Django itself. 
    2525 
    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, {}, {}, ['']) 
    2826runshell = lambda: __import__('django.db.backends.%s.client' % settings.DATABASE_ENGINE, {}, {}, ['']).runshell() 
    2927 
    3028connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS) 
     
    4644def _rollback_on_exception(): 
    4745    from django.db import transaction 
    4846    transaction.rollback_unless_managed() 
    49 dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception) 
     47dispatcher.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 
     1from django.db.backends.introspection import BaseIntrospection 
    32 
    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 = {} 
     3class 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 
     1from django.db.backends.creation import BaseCreation 
     2 
     3class 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  
     1from django.db.backends.introspection import BaseIntrospection 
    12from django.db.backends.mysql_old.base import DatabaseOperations 
    23from MySQLdb import ProgrammingError, OperationalError 
    34from MySQLdb.constants import FIELD_TYPE 
     
    67quote_name = DatabaseOperations().quote_name 
    78foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 
    89 
    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()] 
     10class 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    } 
    1331 
    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 
     32    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()] 
    1836 
    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 
    2541 
    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))]) 
    5648 
    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()) 
    6179 
    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) 
    6384 
    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 
    7686 
    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 
     1from django.db.backends.creation import BaseCreation 
     2 
     3class 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  
     1from django.db.backends.introspection import BaseIntrospection 
    12from django.db.backends.postgresql.base import DatabaseOperations 
    23 
    34quote_name = DatabaseOperations().quote_name 
     
    23 
    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()] 
     4class 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    } 
    1320 
    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()] 
    1831 
    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 
    3936 
    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 
    6857 
    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 
     1from django.db.backends.creation import BaseCreation 
     2 
     3class 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  
     1from django.db.backends.introspection import BaseIntrospection 
    12from django.db.backends.sqlite3.base import DatabaseOperations 
    23 
    34quote_name = DatabaseOperations().quote_name 
     
    23 
    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 key 
    6     # generation. 
    7     cursor.execute(""" 
    8         SELECT name FROM sqlite_master 
    9         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 NotImplementedError 
    20  
    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, unique 
    34     for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]: 
    35         if not unique: 
    36             continue 
    37         cursor.execute('PRAGMA index_info(%s)' % quote_name(index)) 
    38         info = cursor.fetchall() 
    39         # Skip indexes across multiple fields 
    40         if len(info) != 1: 
    41             continue 
    42         name = info[0][2] # seqno, cid, name 
    43         indexes[name]['unique'] = True 
    44     return indexes 
    45  
    46 def _table_info(cursor, name): 
    47     cursor.execute('PRAGMA table_info(%s)' % quote_name(name)) 
    48     # cid, name, type, notnull, dflt_value, pk 
    49     return [{'name': field[1], 
    50              'type': field[2], 
    51              'null_ok': not field[3], 
    52              'pk': field[5]     # undocumented 
    53              } for field in cursor.fetchall()] 
    54  
    55 # Maps SQL types to Django Field types. Some of the SQL types have multiple 
    56 # entries here because SQLite allows for anything and doesn't normalize the 
    57 # 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  
    724# This light wrapper "fakes" a dictionary interface, because some SQLite data 
    735# types include variables in them -- e.g. "varchar(30)" -- and can't be matched 
    746# as a simple dictionary lookup. 
    757class 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     
    7622    def __getitem__(self, key): 
    7723        key = key.lower() 
    7824        try: 
    79             return BASE_DATA_TYPES_REVERSE[key] 
     25            return self.base_data_types_reverse[key] 
    8026        except KeyError: 
     
    8632                return ('CharField', {'max_length': int(m.group(1))}) 
    8733            raise KeyError 
    8834 
    89 DATA_TYPES_REVERSE = FlexibleFieldLookupDict() 
     35class 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  
    11# SQLite doesn't actually support most of these types, but it "does the right 
    22# thing" given more verbose field definitions, so leave them as is so that 
    33# 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 
     4from django.db.backends.creation import BaseCreation 
     5 
     6class 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  
     1from django.db.backends.introspection import BaseIntrospection 
    12from django.db.backends.mysql.base import DatabaseOperations 
    23from MySQLdb import ProgrammingError, OperationalError 
    34from MySQLdb.constants import FIELD_TYPE 
     
    67quote_name = DatabaseOperations().quote_name 
    78foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 
    89 
    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()] 
     10class 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    } 
    1331 
    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 
     32    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()] 
    1836 
    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 
    2541 
    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))]) 
    5648 
    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