Ticket #5461: 5461.patch

File 5461.patch, 86.3 KB (added by brantley, 17 years ago)
  • test/utils.py

     
    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

     
    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

     
    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)
     48 No newline at end of file
  • db/backends/ado_mssql/introspection.py

     
    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

     
    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

     
     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

     
    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

     
     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

     
    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

     
     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

     
    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

     
     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                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: '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 }
     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
  • db/backends/mysql/creation.py

     
    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/oracle/introspection.py

     
     1from django.db.backends.introspection import BaseIntrospection
    12from django.db.backends.oracle.base import DatabaseOperations
    23import re
    34import cx_Oracle
     
    56quote_name = DatabaseOperations().quote_name
    67foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
    78
    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()]
    12 
    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
    17 
    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))])
    24 
    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("""
     9class BaseIntrospection(BaseIntrospection):
     10    data_types_reverse = {
     11        cx_Oracle.CLOB: 'TextField',
     12        cx_Oracle.DATETIME: 'DateTimeField',
     13        cx_Oracle.FIXED_CHAR: 'CharField',
     14        cx_Oracle.NCLOB: 'TextField',
     15        cx_Oracle.NUMBER: 'DecimalField',
     16        cx_Oracle.STRING: 'CharField',
     17        cx_Oracle.TIMESTAMP: 'DateTimeField',
     18    }
     19       
     20    def get_table_list(self, cursor):
     21        "Returns a list of table names in the current database."
     22        cursor.execute("SELECT TABLE_NAME FROM USER_TABLES")
     23        return [row[0].upper() for row in cursor.fetchall()]
     24   
     25    def get_table_description(self, cursor, table_name):
     26        "Returns a description of the table, with the DB-API cursor.description interface."
     27        cursor.execute("SELECT * FROM %s WHERE ROWNUM < 2" % quote_name(table_name))
     28        return cursor.description
     29       
     30    def get_relations(self, cursor, table_name):
     31        """
     32        Returns a dictionary of {field_index: (field_index_other_table, other_table)}
     33        representing all relationships to the given table. Indexes are 0-based.
     34        """
     35        cursor.execute("""
    3136SELECT 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
     37FROM user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb,
     38        user_tab_cols ta, user_tab_cols tb
    3439WHERE  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])
    43 
    44     relations = {}
    45     for row in cursor.fetchall():
    46         relations[row[0]] = (row[2], row[1])
    47     return relations
    48 
    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 = """
     40        ta.table_name = %s AND
     41        ta.column_name = ca.column_name AND
     42        ca.table_name = %s AND
     43        user_constraints.constraint_name = ca.constraint_name AND
     44        user_constraints.r_constraint_name = cb.constraint_name AND
     45        cb.table_name = tb.table_name AND
     46        cb.column_name = tb.column_name AND
     47        ca.position = cb.position""", [table_name, table_name, table_name])
     48       
     49        relations = {}
     50        for row in cursor.fetchall():
     51            relations[row[0]] = (row[2], row[1])
     52        return relations
     53   
     54    def get_indexes(self, cursor, table_name):
     55        """
     56        Returns a dictionary of fieldname -> infodict for the given table,
     57        where each infodict is in the format:
     58            {'primary_key': boolean representing whether it's the primary key,
     59             'unique': boolean representing whether it's a unique index}
     60        """
     61        # This query retrieves each index on the given table, including the
     62        # first associated field name
     63        # "We were in the nick of time; you were in great peril!"
     64        sql = """
    6065WITH primarycols AS (
    6166 SELECT user_cons_columns.table_name, user_cons_columns.column_name, 1 AS PRIMARYCOL
    6267 FROM   user_cons_columns, user_constraints
     
    7681WHERE  allcols.column_name = primarycols.column_name (+) AND
    7782      allcols.column_name = uniquecols.column_name (+)
    7883    """
    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
    88 
    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 }
     84        cursor.execute(sql, [table_name, table_name])
     85        indexes = {}
     86        for row in cursor.fetchall():
     87            # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
     88            # a string of space-separated integers. This designates the field
     89            # indexes (1-based) of the fields that have indexes on the table.
     90            # Here, we skip any indexes across multiple fields.
     91            indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]}
     92        return indexes
     93       
     94    def _name_to_index(self, cursor, table_name):
     95        """
     96        Returns a dictionary of {field_name: field_index} for the given table.
     97        Indexes are 0-based.
     98        """
     99        return dict([(d[0], i) for i, d in enumerate(self.get_table_description(cursor, table_name))])
  • db/backends/oracle/creation.py

     
    11import sys, time
    22from django.core import management
     3from django.db.backends.creation import BaseCreation
    34
    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 DATA_TYPES = {
    9     'AutoField':                    'NUMBER(11)',
    10     'BooleanField':                 'NUMBER(1) CHECK (%(column)s IN (0,1))',
    11     'CharField':                    'NVARCHAR2(%(max_length)s)',
    12     'CommaSeparatedIntegerField':   'VARCHAR2(%(max_length)s)',
    13     'DateField':                    'DATE',
    14     'DateTimeField':                'TIMESTAMP',
    15     'DecimalField':                 'NUMBER(%(max_digits)s, %(decimal_places)s)',
    16     'FileField':                    'NVARCHAR2(100)',
    17     'FilePathField':                'NVARCHAR2(100)',
    18     'FloatField':                   'DOUBLE PRECISION',
    19     'ImageField':                   'NVARCHAR2(100)',
    20     'IntegerField':                 'NUMBER(11)',
    21     'IPAddressField':               'VARCHAR2(15)',
    22     'NullBooleanField':             'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
    23     'OneToOneField':                'NUMBER(11)',
    24     'PhoneNumberField':             'VARCHAR2(20)',
    25     'PositiveIntegerField':         'NUMBER(11) CHECK (%(column)s >= 0)',
    26     'PositiveSmallIntegerField':    'NUMBER(11) CHECK (%(column)s >= 0)',
    27     'SlugField':                    'NVARCHAR2(50)',
    28     'SmallIntegerField':            'NUMBER(11)',
    29     'TextField':                    'NCLOB',
    30     'TimeField':                    'TIMESTAMP',
    31     'URLField':                     'VARCHAR2(200)',
    32     'USStateField':                 'CHAR(2)',
    33 }
     5class Creation(BaseCreation):
     6    # This dictionary maps Field objects to their associated Oracle column
     7    # types, as strings. Column-type strings can contain format strings; they'll
     8    # be interpolated against the values of Field.__dict__ before being output.
     9    # If a column type is set to None, it won't be included in the output.
     10    data_types = {
     11        'AutoField':                    'NUMBER(11)',
     12        'BooleanField':                 'NUMBER(1) CHECK (%(column)s IN (0,1))',
     13        'CharField':                    'NVARCHAR2(%(max_length)s)',
     14        'CommaSeparatedIntegerField':   'VARCHAR2(%(max_length)s)',
     15        'DateField':                    'DATE',
     16        'DateTimeField':                'TIMESTAMP',
     17        'DecimalField':                 'NUMBER(%(max_digits)s, %(decimal_places)s)',
     18        'FileField':                    'NVARCHAR2(100)',
     19        'FilePathField':                'NVARCHAR2(100)',
     20        'FloatField':                   'DOUBLE PRECISION',
     21        'ImageField':                   'NVARCHAR2(100)',
     22        'IntegerField':                 'NUMBER(11)',
     23        'IPAddressField':               'VARCHAR2(15)',
     24        'NullBooleanField':             'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
     25        'OneToOneField':                'NUMBER(11)',
     26        'PhoneNumberField':             'VARCHAR2(20)',
     27        'PositiveIntegerField':         'NUMBER(11) CHECK (%(column)s >= 0)',
     28        'PositiveSmallIntegerField':    'NUMBER(11) CHECK (%(column)s >= 0)',
     29        'SlugField':                    'NVARCHAR2(50)',
     30        'SmallIntegerField':            'NUMBER(11)',
     31        'TextField':                    'NCLOB',
     32        'TimeField':                    'TIMESTAMP',
     33        'URLField':                     'VARCHAR2(200)',
     34        'USStateField':                 'CHAR(2)',
     35    }
    3436
    35 TEST_DATABASE_PREFIX = 'test_'
    36 PASSWORD = 'Im_a_lumberjack'
    37 REMEMBER = {}
     37    def create_test_db(settings, connection, verbosity=1, autoclobber=False):
     38        TEST_DATABASE_NAME = _test_database_name(settings)
     39        TEST_DATABASE_USER = _test_database_user(settings)
     40        TEST_DATABASE_PASSWD = _test_database_passwd(settings)
     41        TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings)
     42        TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings)
    3843
    39 def create_test_db(settings, connection, verbosity=1, autoclobber=False):
    40     TEST_DATABASE_NAME = _test_database_name(settings)
    41     TEST_DATABASE_USER = _test_database_user(settings)
    42     TEST_DATABASE_PASSWD = _test_database_passwd(settings)
    43     TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings)
    44     TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings)
     44        parameters = {
     45            'dbname': TEST_DATABASE_NAME,
     46            'user': TEST_DATABASE_USER,
     47            'password': TEST_DATABASE_PASSWD,
     48            'tblspace': TEST_DATABASE_TBLSPACE,
     49            'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP,
     50        }
    4551
    46     parameters = {
    47         'dbname': TEST_DATABASE_NAME,
    48         'user': TEST_DATABASE_USER,
    49         'password': TEST_DATABASE_PASSWD,
    50         'tblspace': TEST_DATABASE_TBLSPACE,
    51         'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP,
    52         }
     52        REMEMBER['user'] = settings.DATABASE_USER
     53        REMEMBER['passwd'] = settings.DATABASE_PASSWORD
    5354
    54     REMEMBER['user'] = settings.DATABASE_USER
    55     REMEMBER['passwd'] = settings.DATABASE_PASSWORD
     55        cursor = connection.cursor()
     56        if _test_database_create(settings):
     57            if verbosity >= 1:
     58                print 'Creating test database...'
     59            try:
     60                _create_test_db(cursor, parameters, verbosity)
     61            except Exception, e:
     62                sys.stderr.write("Got an error creating the test database: %s\n" % e)
     63                if not autoclobber:
     64                    confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)
     65                if autoclobber or confirm == 'yes':
     66                    try:
     67                        if verbosity >= 1:
     68                            print "Destroying old test database..."
     69                        _destroy_test_db(cursor, parameters, verbosity)
     70                        if verbosity >= 1:
     71                            print "Creating test database..."
     72                        _create_test_db(cursor, parameters, verbosity)
     73                    except Exception, e:
     74                        sys.stderr.write("Got an error recreating the test database: %s\n" % e)
     75                        sys.exit(2)
     76                else:
     77                    print "Tests cancelled."
     78                    sys.exit(1)
    5679
    57     cursor = connection.cursor()
    58     if _test_database_create(settings):
    59         if verbosity >= 1:
    60             print 'Creating test database...'
    61         try:
    62             _create_test_db(cursor, parameters, verbosity)
    63         except Exception, e:
    64             sys.stderr.write("Got an error creating the test database: %s\n" % e)
    65             if not autoclobber:
    66                 confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)
    67             if autoclobber or confirm == 'yes':
    68                 try:
    69                     if verbosity >= 1:
    70                         print "Destroying old test database..."
    71                     _destroy_test_db(cursor, parameters, verbosity)
    72                     if verbosity >= 1:
    73                         print "Creating test database..."
    74                     _create_test_db(cursor, parameters, verbosity)
    75                 except Exception, e:
    76                     sys.stderr.write("Got an error recreating the test database: %s\n" % e)
    77                     sys.exit(2)
    78             else:
    79                 print "Tests cancelled."
    80                 sys.exit(1)
     80        if _test_user_create(settings):
     81            if verbosity >= 1:
     82                print "Creating test user..."
     83            try:
     84                _create_test_user(cursor, parameters, verbosity)
     85            except Exception, e:
     86                sys.stderr.write("Got an error creating the test user: %s\n" % e)
     87                if not autoclobber:
     88                    confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER)
     89                if autoclobber or confirm == 'yes':
     90                    try:
     91                        if verbosity >= 1:
     92                            print "Destroying old test user..."
     93                        _destroy_test_user(cursor, parameters, verbosity)
     94                        if verbosity >= 1:
     95                            print "Creating test user..."
     96                        _create_test_user(cursor, parameters, verbosity)
     97                    except Exception, e:
     98                        sys.stderr.write("Got an error recreating the test user: %s\n" % e)
     99                        sys.exit(2)
     100                else:
     101                    print "Tests cancelled."
     102                    sys.exit(1)
    81103
    82     if _test_user_create(settings):
    83         if verbosity >= 1:
    84             print "Creating test user..."
    85         try:
    86             _create_test_user(cursor, parameters, verbosity)
    87         except Exception, e:
    88             sys.stderr.write("Got an error creating the test user: %s\n" % e)
    89             if not autoclobber:
    90                 confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER)
    91             if autoclobber or confirm == 'yes':
    92                 try:
    93                     if verbosity >= 1:
    94                         print "Destroying old test user..."
    95                     _destroy_test_user(cursor, parameters, verbosity)
    96                     if verbosity >= 1:
    97                         print "Creating test user..."
    98                     _create_test_user(cursor, parameters, verbosity)
    99                 except Exception, e:
    100                     sys.stderr.write("Got an error recreating the test user: %s\n" % e)
    101                     sys.exit(2)
    102             else:
    103                 print "Tests cancelled."
    104                 sys.exit(1)
     104        connection.close()
     105        settings.DATABASE_USER = TEST_DATABASE_USER
     106        settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD
    105107
    106     connection.close()
    107     settings.DATABASE_USER = TEST_DATABASE_USER
    108     settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD
     108        management.call_command('syncdb', verbosity=verbosity, interactive=False)
    109109
    110     management.call_command('syncdb', verbosity=verbosity, interactive=False)
     110        # Get a cursor (even though we don't need one yet). This has
     111        # the side effect of initializing the test database.
     112        cursor = connection.cursor()
    111113
    112     # Get a cursor (even though we don't need one yet). This has
    113     # the side effect of initializing the test database.
    114     cursor = connection.cursor()
     114    def destroy_test_db(settings, connection, old_database_name, verbosity=1):
     115        connection.close()
    115116
    116 def destroy_test_db(settings, connection, old_database_name, verbosity=1):
    117     connection.close()
     117        TEST_DATABASE_NAME = _test_database_name(settings)
     118        TEST_DATABASE_USER = _test_database_user(settings)
     119        TEST_DATABASE_PASSWD = _test_database_passwd(settings)
     120        TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings)
     121        TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings)
    118122
    119     TEST_DATABASE_NAME = _test_database_name(settings)
    120     TEST_DATABASE_USER = _test_database_user(settings)
    121     TEST_DATABASE_PASSWD = _test_database_passwd(settings)
    122     TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings)
    123     TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings)
     123        settings.DATABASE_NAME = old_database_name
     124        settings.DATABASE_USER = REMEMBER['user']
     125        settings.DATABASE_PASSWORD = REMEMBER['passwd']
    124126
    125     settings.DATABASE_NAME = old_database_name
    126     settings.DATABASE_USER = REMEMBER['user']
    127     settings.DATABASE_PASSWORD = REMEMBER['passwd']
     127        parameters = {
     128            'dbname': TEST_DATABASE_NAME,
     129            'user': TEST_DATABASE_USER,
     130            'password': TEST_DATABASE_PASSWD,
     131            'tblspace': TEST_DATABASE_TBLSPACE,
     132            'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP,
     133        }
    128134
    129     parameters = {
    130         'dbname': TEST_DATABASE_NAME,
    131         'user': TEST_DATABASE_USER,
    132         'password': TEST_DATABASE_PASSWD,
    133         'tblspace': TEST_DATABASE_TBLSPACE,
    134         'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP,
    135         }
     135        REMEMBER['user'] = settings.DATABASE_USER
     136        REMEMBER['passwd'] = settings.DATABASE_PASSWORD
    136137
    137     REMEMBER['user'] = settings.DATABASE_USER
    138     REMEMBER['passwd'] = settings.DATABASE_PASSWORD
     138        cursor = connection.cursor()
     139        time.sleep(1) # To avoid "database is being accessed by other users" errors.
     140        if _test_user_create(settings):
     141            if verbosity >= 1:
     142                print 'Destroying test user...'
     143            _destroy_test_user(cursor, parameters, verbosity)
     144        if _test_database_create(settings):
     145            if verbosity >= 1:
     146                print 'Destroying test database...'
     147            _destroy_test_db(cursor, parameters, verbosity)
     148        connection.close()
    139149
    140     cursor = connection.cursor()
    141     time.sleep(1) # To avoid "database is being accessed by other users" errors.
    142     if _test_user_create(settings):
    143         if verbosity >= 1:
    144             print 'Destroying test user...'
    145         _destroy_test_user(cursor, parameters, verbosity)
    146     if _test_database_create(settings):
    147         if verbosity >= 1:
    148             print 'Destroying test database...'
    149         _destroy_test_db(cursor, parameters, verbosity)
    150     connection.close()
     150# Seriously?
     151TEST_DATABASE_PREFIX = 'test_'
     152PASSWORD = 'Im_a_lumberjack'
     153REMEMBER = {}
    151154
    152155def _create_test_db(cursor, parameters, verbosity):
    153156    if verbosity >= 2:
  • db/backends/__init__.py

     
    3838    def make_debug_cursor(self, cursor):
    3939        from django.db.backends import util
    4040        return util.CursorDebugWrapper(cursor, self)
     41       
     42    def _get_creation(self):
     43        if not hasattr(self, '_creation'):
     44            from django.conf import settings
     45            module = __import__('django.db.backends.%s.creation' % settings.DATABASE_ENGINE, {}, {}, [''])
     46            self._creation = module.Creation()
     47        return self._creation
     48    creation = property(fget=_get_creation)
     49       
     50    def _get_introspection(self):
     51        if not hasattr(self, '_introspection'):
     52            from django.conf import settings
     53            module = __import__('django.db.backends.%s.introspection' % settings.DATABASE_ENGINE, {}, {}, [''])
     54            self._introspection = module.Introspection()
     55        return self._introspection
     56    introspection = property(_get_introspection)
    4157
    4258class BaseDatabaseFeatures(object):
    4359    allows_group_by_ordinal = True
  • db/backends/postgresql_psycopg2/introspection.py

     
     1from django.db.backends.introspection import BaseIntrospection
    12from django.db.backends.postgresql_psycopg2.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    }
     20   
     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()]
    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_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
    1836
    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         # row[0] and row[1] are single-item lists, so grab the single item.
    34         relations[row[0][0] - 1] = (row[1][0] - 1, row[2])
    35     return relations
     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            # row[0] and row[1] are single-item lists, so grab the single item.
     52            relations[row[0][0] - 1] = (row[1][0] - 1, row[2])
     53        return relations
    3654
    37 def get_indexes(cursor, table_name):
    38     """
    39     Returns a dictionary of fieldname -> infodict for the given table,
    40     where each infodict is in the format:
    41         {'primary_key': boolean representing whether it's the primary key,
    42          'unique': boolean representing whether it's a unique index}
    43     """
    44     # This query retrieves each index on the given table, including the
    45     # first associated field name
    46     cursor.execute("""
    47         SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
    48         FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
    49             pg_catalog.pg_index idx, pg_catalog.pg_attribute attr
    50         WHERE c.oid = idx.indrelid
    51             AND idx.indexrelid = c2.oid
    52             AND attr.attrelid = c.oid
    53             AND attr.attnum = idx.indkey[0]
    54             AND c.relname = %s""", [table_name])
    55     indexes = {}
    56     for row in cursor.fetchall():
    57         # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
    58         # a string of space-separated integers. This designates the field
    59         # indexes (1-based) of the fields that have indexes on the table.
    60         # Here, we skip any indexes across multiple fields.
    61         if ' ' in row[1]:
    62             continue
    63         indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
    64     return indexes
     55    def get_indexes(self, cursor, table_name):
     56        """
     57        Returns a dictionary of fieldname -> infodict for the given table,
     58        where each infodict is in the format:
     59            {'primary_key': boolean representing whether it's the primary key,
     60             'unique': boolean representing whether it's a unique index}
     61        """
     62        # This query retrieves each index on the given table, including the
     63        # first associated field name
     64        cursor.execute("""
     65            SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
     66            FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
     67                pg_catalog.pg_index idx, pg_catalog.pg_attribute attr
     68            WHERE c.oid = idx.indrelid
     69                AND idx.indexrelid = c2.oid
     70                AND attr.attrelid = c.oid
     71                AND attr.attnum = idx.indkey[0]
     72                AND c.relname = %s""", [table_name])
     73        indexes = {}
     74        for row in cursor.fetchall():
     75            # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
     76            # a string of space-separated integers. This designates the field
     77            # indexes (1-based) of the fields that have indexes on the table.
     78            # Here, we skip any indexes across multiple fields.
     79            if ' ' in row[1]:
     80                continue
     81            indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
     82        return indexes
    6583
    66 # Maps type codes to Django Field types.
    67 DATA_TYPES_REVERSE = {
    68     16: 'BooleanField',
    69     21: 'SmallIntegerField',
    70     23: 'IntegerField',
    71     25: 'TextField',
    72     701: 'FloatField',
    73     869: 'IPAddressField',
    74     1043: 'CharField',
    75     1082: 'DateField',
    76     1083: 'TimeField',
    77     1114: 'DateTimeField',
    78     1184: 'DateTimeField',
    79     1266: 'TimeField',
    80     1700: 'DecimalField',
    81 }
  • db/backends/dummy/introspection.py

     
     1from django.db.backends.introspection import BaseIntrospection
    12from django.db.backends.dummy.base import complain
    23
    3 get_table_list = complain
    4 get_table_description = complain
    5 get_relations = complain
    6 get_indexes = complain
    7 
    8 DATA_TYPES_REVERSE = {}
     4class Introspection(BaseIntrospection):
     5    get_table_list = complain
     6    get_table_description = complain
     7    get_relations = complain
     8    get_indexes = complain
  • db/backends/dummy/creation.py

     
    1 DATA_TYPES = {}
     1from django.db.backends.creation import BaseCreation
     2
     3class Creation(BaseCreation):
     4    data_types = {}
     5 No newline at end of file
  • db/backends/creation.py

     
    44    database *creation*, such as the column types to use for particular Django
    55    Fields.
    66    """
    7     pass
     7    data_types = {}     # 'ModelField': 'database_type',
     8   
     9    def create_test_db(self, settings, connection, verbosity=1, autoclobber=False):
     10        raise NotImplementedError()
     11       
     12    def destroy_test_db(self, settings, connection, old_database_name, verbosity=1):
     13        raise NotImplementedError()
     14 No newline at end of file
  • core/management/commands/inspectdb.py

     
    1313            raise CommandError("Database inspection isn't supported for the currently selected database backend.")
    1414
    1515    def handle_inspection(self):
    16         from django.db import connection, get_introspection_module
     16        from django.db import connection
    1717        import keyword
    1818
    19         introspection_module = get_introspection_module()
    20 
    2119        table2model = lambda table_name: table_name.title().replace('_', '')
    2220
    2321        cursor = connection.cursor()
     
    3230        yield ''
    3331        yield 'from django.db import models'
    3432        yield ''
    35         for table_name in introspection_module.get_table_list(cursor):
     33        for table_name in connection.introspection.get_table_list(cursor):
    3634            yield 'class %s(models.Model):' % table2model(table_name)
    3735            try:
    38                 relations = introspection_module.get_relations(cursor, table_name)
     36                relations = connection.introspection.get_relations(cursor, table_name)
    3937            except NotImplementedError:
    4038                relations = {}
    4139            try:
    42                 indexes = introspection_module.get_indexes(cursor, table_name)
     40                indexes = connection.introspection.get_indexes(cursor, table_name)
    4341            except NotImplementedError:
    4442                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)):
    4644                att_name = row[0].lower()
    4745                comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
    4846                extra_params = {}  # Holds Field parameters such as 'db_column'.
     
    6563                        extra_params['db_column'] = att_name
    6664                else:
    6765                    try:
    68                         field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]
     66                        field_type = connection.introspection.data_types_reverse[row[1]]
    6967                    except KeyError:
    7068                        field_type = 'TextField'
    7169                        comment_notes.append('This field type is a guess.')
    7270
    73                     # This is a hook for DATA_TYPES_REVERSE to return a tuple of
     71                    # This is a hook for data_types_reverse to return a tuple of
    7472                    # (field_type, extra_params_dict).
    7573                    if type(field_type) is tuple:
    7674                        field_type, new_params = field_type
  • core/management/commands/syncdb.py

     
    2121    def handle_noargs(self, **options):
    2222        from django.db import connection, transaction, models
    2323        from django.conf import settings
    24         from django.core.management.sql import table_list, 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_signal
     24        from django.core.management.sql import 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_signal
    2525
    2626        verbosity = int(options.get('verbosity', 1))
    2727        interactive = options.get('interactive')
     
    4040
    4141        # Get a list of all existing database tables,
    4242        # so we know what needs to be added.
    43         table_list = table_list()
     43        table_list = connection.introspection.get_table_list(cursor)
    4444        if connection.features.uses_case_insensitive_names:
    4545            table_name_converter = str.upper
    4646        else:
  • core/management/sql.py

     
    77except NameError:
    88    from sets import Set as set   # Python 2.3 fallback
    99
    10 def table_list():
    11     "Returns a list of all table names that exist in the database."
    12     from django.db import connection, get_introspection_module
    13     cursor = connection.cursor()
    14     return get_introspection_module().get_table_list(cursor)
    15 
    1610def django_table_list(only_existing=False):
    1711    """
    1812    Returns a list of all table names that have associated Django models and
     
    2216    that actually exist in the database.
    2317    """
    2418    from django.db import models
     19    from django.db import connection
    2520    tables = []
    2621    for app in models.get_apps():
    2722        for model in models.get_models(app):
    2823            tables.append(model._meta.db_table)
    2924            tables.extend([f.m2m_db_table() for f in model._meta.many_to_many])
    3025    if only_existing:
    31         existing = table_list()
     26        existing = connection.introspection.get_table_list(connection.cursor())
    3227        tables = [t for t in tables if t in existing]
    3328    return tables
    3429
     
    6661
    6762def sql_create(app, style):
    6863    "Returns a list of the CREATE TABLE SQL statements for the given app."
    69     from django.db import models
     64    from django.db import connection, models
    7065    from django.conf import settings
    7166
    7267    if settings.DATABASE_ENGINE == 'dummy':
     
    8277    # we can be conservative).
    8378    app_models = models.get_models(app)
    8479    final_output = []
    85     known_models = set([model for model in installed_models(table_list()) if model not in app_models])
     80    tables = connection.introspection.get_table_list(connection.cursor())
     81    known_models = set([model for model in installed_models(tables) if model not in app_models])
    8682    pending_references = {}
    8783
    8884    for model in app_models:
     
    114110
    115111def sql_delete(app, style):
    116112    "Returns a list of the DROP TABLE SQL statements for the given app."
    117     from django.db import connection, models, get_introspection_module
     113    from django.db import connection, models
    118114    from django.db.backends.util import truncate_name
    119     introspection = get_introspection_module()
    120115
    121116    # This should work even if a connection isn't available
    122117    try:
     
    126121
    127122    # Figure out which tables already exist
    128123    if cursor:
    129         table_names = introspection.get_table_list(cursor)
     124        table_names = connection.introspection.get_table_list(cursor)
    130125    else:
    131126        table_names = []
    132127    if connection.features.uses_case_insensitive_names:
     
    211206    if only_django:
    212207        tables = django_table_list()
    213208    else:
    214         tables = table_list()
     209        tables = connection.introspection.get_table_list(connection.cursor())
    215210    statements = connection.ops.sql_flush(style, tables, sequence_list())
    216211    return statements
    217212
Back to Top