Ticket #5461: 5461-r8225.2.diff

File 5461-r8225.2.diff, 167.1 KB (added by Russell Keith-Magee, 16 years ago)

rc2 for Creation backend patch - mysql/validation.py was missing from rc1

  • django/test/simple.py

     
    33from django.db.models import get_app, get_apps
    44from django.test import _doctest as doctest
    55from django.test.utils import setup_test_environment, teardown_test_environment
    6 from django.test.utils import create_test_db, destroy_test_db
    76from django.test.testcases import OutputChecker, DocTestRunner
    87
    98# The module name for tests outside models.py
     
    139138        suite.addTest(test)
    140139
    141140    old_name = settings.DATABASE_NAME
    142     create_test_db(verbosity, autoclobber=not interactive)
     141    from django.db import connection
     142    connection.creation.create_test_db(verbosity, autoclobber=not interactive)
    143143    result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
    144     destroy_test_db(old_name, verbosity)
     144    connection.creation.destroy_test_db(old_name, verbosity)
    145145   
    146146    teardown_test_environment()
    147147   
  • django/test/utils.py

     
    11import sys, time, os
    22from django.conf import settings
    3 from django.db import connection, get_creation_module
     3from django.db import connection
    44from django.core import mail
    5 from django.core.management import call_command
    65from django.test import signals
    76from django.template import Template
    87from django.utils.translation import deactivate
    98
    10 # The prefix to put on the default database name when creating
    11 # the test database.
    12 TEST_DATABASE_PREFIX = 'test_'
    13 
    149def instrumented_test_render(self, context):
    1510    """
    1611    An instrumented Template render method, providing a signal
     
    7065
    7166    del mail.outbox
    7267
    73 def _set_autocommit(connection):
    74     "Make sure a connection is in autocommit mode."
    75     if hasattr(connection.connection, "autocommit"):
    76         if callable(connection.connection.autocommit):
    77             connection.connection.autocommit(True)
    78         else:
    79             connection.connection.autocommit = True
    80     elif hasattr(connection.connection, "set_isolation_level"):
    81         connection.connection.set_isolation_level(0)
    82 
    83 def get_mysql_create_suffix():
    84     suffix = []
    85     if settings.TEST_DATABASE_CHARSET:
    86         suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET)
    87     if settings.TEST_DATABASE_COLLATION:
    88         suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION)
    89     return ' '.join(suffix)
    90 
    91 def get_postgresql_create_suffix():
    92     assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time."
    93     if settings.TEST_DATABASE_CHARSET:
    94         return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET
    95     return ''
    96 
    97 def create_test_db(verbosity=1, autoclobber=False):
    98     """
    99     Creates a test database, prompting the user for confirmation if the
    100     database already exists. Returns the name of the test database created.
    101     """
    102     # If the database backend wants to create the test DB itself, let it
    103     creation_module = get_creation_module()
    104     if hasattr(creation_module, "create_test_db"):
    105         creation_module.create_test_db(settings, connection, verbosity, autoclobber)
    106         return
    107 
    108     if verbosity >= 1:
    109         print "Creating test database..."
    110     # If we're using SQLite, it's more convenient to test against an
    111     # in-memory database. Using the TEST_DATABASE_NAME setting you can still choose
    112     # to run on a physical database.
    113     if settings.DATABASE_ENGINE == "sqlite3":
    114         if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:":
    115             TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
    116             # Erase the old test database
    117             if verbosity >= 1:
    118                 print "Destroying old test database..."
    119             if os.access(TEST_DATABASE_NAME, os.F_OK):
    120                 if not autoclobber:
    121                     confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)
    122                 if autoclobber or confirm == 'yes':
    123                   try:
    124                       if verbosity >= 1:
    125                           print "Destroying old test database..."
    126                       os.remove(TEST_DATABASE_NAME)
    127                   except Exception, e:
    128                       sys.stderr.write("Got an error deleting the old test database: %s\n" % e)
    129                       sys.exit(2)
    130                 else:
    131                     print "Tests cancelled."
    132                     sys.exit(1)
    133             if verbosity >= 1:
    134                 print "Creating test database..."
    135         else:
    136             TEST_DATABASE_NAME = ":memory:"
    137     else:
    138         suffix = {
    139             'postgresql': get_postgresql_create_suffix,
    140             'postgresql_psycopg2': get_postgresql_create_suffix,
    141             'mysql': get_mysql_create_suffix,
    142         }.get(settings.DATABASE_ENGINE, lambda: '')()
    143         if settings.TEST_DATABASE_NAME:
    144             TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
    145         else:
    146             TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
    147 
    148         qn = connection.ops.quote_name
    149 
    150         # Create the test database and connect to it. We need to autocommit
    151         # if the database supports it because PostgreSQL doesn't allow
    152         # CREATE/DROP DATABASE statements within transactions.
    153         cursor = connection.cursor()
    154         _set_autocommit(connection)
    155         try:
    156             cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))
    157         except Exception, e:
    158             sys.stderr.write("Got an error creating the test database: %s\n" % e)
    159             if not autoclobber:
    160                 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)
    161             if autoclobber or confirm == 'yes':
    162                 try:
    163                     if verbosity >= 1:
    164                         print "Destroying old test database..."
    165                     cursor.execute("DROP DATABASE %s" % qn(TEST_DATABASE_NAME))
    166                     if verbosity >= 1:
    167                         print "Creating test database..."
    168                     cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))
    169                 except Exception, e:
    170                     sys.stderr.write("Got an error recreating the test database: %s\n" % e)
    171                     sys.exit(2)
    172             else:
    173                 print "Tests cancelled."
    174                 sys.exit(1)
    175 
    176     connection.close()
    177     settings.DATABASE_NAME = TEST_DATABASE_NAME
    178 
    179     call_command('syncdb', verbosity=verbosity, interactive=False)
    180 
    181     if settings.CACHE_BACKEND.startswith('db://'):
    182         cache_name = settings.CACHE_BACKEND[len('db://'):]
    183         call_command('createcachetable', cache_name)
    184 
    185     # Get a cursor (even though we don't need one yet). This has
    186     # the side effect of initializing the test database.
    187     cursor = connection.cursor()
    188 
    189     return TEST_DATABASE_NAME
    190 
    191 def destroy_test_db(old_database_name, verbosity=1):
    192     # If the database wants to drop the test DB itself, let it
    193     creation_module = get_creation_module()
    194     if hasattr(creation_module, "destroy_test_db"):
    195         creation_module.destroy_test_db(settings, connection, old_database_name, verbosity)
    196         return
    197 
    198     if verbosity >= 1:
    199         print "Destroying test database..."
    200     connection.close()
    201     TEST_DATABASE_NAME = settings.DATABASE_NAME
    202     settings.DATABASE_NAME = old_database_name
    203     if settings.DATABASE_ENGINE == "sqlite3":
    204         if TEST_DATABASE_NAME and TEST_DATABASE_NAME != ":memory:":
    205             # Remove the SQLite database file
    206             os.remove(TEST_DATABASE_NAME)
    207     else:
    208         # Remove the test database to clean up after
    209         # ourselves. Connect to the previous database (not the test database)
    210         # to do so, because it's not allowed to delete a database while being
    211         # connected to it.
    212         cursor = connection.cursor()
    213         _set_autocommit(connection)
    214         time.sleep(1) # To avoid "database is being accessed by other users" errors.
    215         cursor.execute("DROP DATABASE %s" % connection.ops.quote_name(TEST_DATABASE_NAME))
    216         connection.close()
  • django/db/models/fields/__init__.py

     
    77except ImportError:
    88    from django.utils import _decimal as decimal    # for Python 2.3
    99
    10 from django.db import connection, get_creation_module
     10from django.db import connection
    1111from django.db.models import signals
    1212from django.db.models.query_utils import QueryWrapper
    1313from django.dispatch import dispatcher
     
    145145        # as the TextField Django field type, which means XMLField's
    146146        # get_internal_type() returns 'TextField'.
    147147        #
    148         # But the limitation of the get_internal_type() / DATA_TYPES approach
     148        # But the limitation of the get_internal_type() / data_types approach
    149149        # is that it cannot handle database column types that aren't already
    150150        # mapped to one of the built-in Django field types. In this case, you
    151151        # can implement db_type() instead of get_internal_type() to specify
    152152        # exactly which wacky database column type you want to use.
    153153        data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
    154154        try:
    155             return get_creation_module().DATA_TYPES[self.get_internal_type()] % data
     155            return connection.creation.data_types[self.get_internal_type()] % data
    156156        except KeyError:
    157157            return None
    158158
  • django/db/__init__.py

     
    1414    # backends that ships with Django, so look there first.
    1515    _import_path = 'django.db.backends.'
    1616    backend = __import__('%s%s.base' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])
    17     creation = __import__('%s%s.creation' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])
    1817except ImportError, e:
    1918    # If the import failed, we might be looking for a database backend
    2019    # distributed external to Django. So we'll try that next.
    2120    try:
    2221        _import_path = ''
    2322        backend = __import__('%s.base' % settings.DATABASE_ENGINE, {}, {}, [''])
    24         creation = __import__('%s.creation' % settings.DATABASE_ENGINE, {}, {}, [''])
    2523    except ImportError, e_user:
    2624        # The database backend wasn't found. Display a helpful error message
    2725        # listing all possible (built-in) database backends.
     
    2927        available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')]
    3028        available_backends.sort()
    3129        if settings.DATABASE_ENGINE not in available_backends:
    32             raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s" % \
    33                 (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends)))
     30            raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s\nError was: %s" % \
     31                (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends, e_user)))
    3432        else:
    3533            raise # If there's some other error, this must be an error in Django itself.
    3634
    37 def _import_database_module(import_path='', module_name=''):
    38     """Lazily import a database module when requested."""
    39     return __import__('%s%s.%s' % (import_path, settings.DATABASE_ENGINE, module_name), {}, {}, [''])
    40 
    41 # We don't want to import the introspect module unless someone asks for it, so
    42 # lazily load it on demmand.
    43 get_introspection_module = curry(_import_database_module, _import_path, 'introspection')
    44 
    45 def get_creation_module():
    46     return creation
    47 
    48 # We want runshell() to work the same way, but we have to treat it a
    49 # little differently (since it just runs instead of returning a module like
    50 # the above) and wrap the lazily-loaded runshell() method.
    51 runshell = lambda: _import_database_module(_import_path, "client").runshell()
    52 
    5335# Convenient aliases for backend bits.
    5436connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS)
    5537DatabaseError = backend.DatabaseError
  • django/db/backends/postgresql/base.py

     
    44Requires psycopg 1: http://initd.org/projects/psycopg1
    55"""
    66
     7from django.db.backends import BaseDatabaseFeatures
     8from django.db.backends import BaseDatabaseValidation
     9from django.db.backends import BaseDatabaseWrapper
     10from django.db.backends import util
     11from django.db.backends.postgresql.client import DatabaseClient
     12from django.db.backends.postgresql.creation import DatabaseCreation
     13from django.db.backends.postgresql.introspection import DatabaseIntrospection
     14from django.db.backends.postgresql.operations import DatabaseOperations
    715from django.utils.encoding import smart_str, smart_unicode
    8 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, util
    9 from django.db.backends.postgresql.operations import DatabaseOperations
     16
    1017try:
    1118    import psycopg as Database
    1219except ImportError, e:
     
    6269class DatabaseFeatures(BaseDatabaseFeatures):
    6370    pass # This backend uses all the defaults.
    6471
     72class DatabaseValidation(BaseDatabaseValidation):
     73    pass
     74
    6575class DatabaseWrapper(BaseDatabaseWrapper):
    66     features = DatabaseFeatures()
    67     ops = DatabaseOperations()
    6876    operators = {
    6977        'exact': '= %s',
    7078        'iexact': 'ILIKE %s',
     
    8290        'iendswith': 'ILIKE %s',
    8391    }
    8492
     93    def __init__(self, *args, **kwargs):
     94        super(DatabaseWrapper, self).__init__(*args, **kwargs)
     95       
     96        self.features = DatabaseFeatures()
     97        self.ops = DatabaseOperations()
     98        self.client = DatabaseClient()
     99        self.creation = DatabaseCreation(self)
     100        self.introspection = DatabaseIntrospection(self)
     101        self.validation = DatabaseValidation()
     102
    85103    def _cursor(self, settings):
    86104        set_tz = False
    87105        if self.connection is None:
  • django/db/backends/postgresql/client.py

     
     1from django.db.backends import BaseDatabaseClient
    12from django.conf import settings
    23import os
    34
    4 def runshell():
    5     args = ['psql']
    6     if settings.DATABASE_USER:
    7         args += ["-U", settings.DATABASE_USER]
    8     if settings.DATABASE_PASSWORD:
    9         args += ["-W"]
    10     if settings.DATABASE_HOST:
    11         args.extend(["-h", settings.DATABASE_HOST])
    12     if settings.DATABASE_PORT:
    13         args.extend(["-p", str(settings.DATABASE_PORT)])
    14     args += [settings.DATABASE_NAME]
    15     os.execvp('psql', args)
     5class DatabaseClient(BaseDatabaseClient):
     6    def runshell(self):
     7        args = ['psql']
     8        if settings.DATABASE_USER:
     9            args += ["-U", settings.DATABASE_USER]
     10        if settings.DATABASE_PASSWORD:
     11            args += ["-W"]
     12        if settings.DATABASE_HOST:
     13            args.extend(["-h", settings.DATABASE_HOST])
     14        if settings.DATABASE_PORT:
     15            args.extend(["-p", str(settings.DATABASE_PORT)])
     16        args += [settings.DATABASE_NAME]
     17        os.execvp('psql', args)
  • django/db/backends/postgresql/introspection.py

     
    1 from django.db.backends.postgresql.base import DatabaseOperations
     1from django.db.backends import BaseDatabaseIntrospection
    22
    3 quote_name = DatabaseOperations().quote_name
     3class DatabaseIntrospection(BaseDatabaseIntrospection):
     4    # Maps type codes to Django Field types.
     5    data_types_reverse = {
     6        16: 'BooleanField',
     7        21: 'SmallIntegerField',
     8        23: 'IntegerField',
     9        25: 'TextField',
     10        701: 'FloatField',
     11        869: 'IPAddressField',
     12        1043: 'CharField',
     13        1082: 'DateField',
     14        1083: 'TimeField',
     15        1114: 'DateTimeField',
     16        1184: 'DateTimeField',
     17        1266: 'TimeField',
     18        1700: 'DecimalField',
     19    }
     20       
     21    def 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()]
    431
    5 def get_table_list(cursor):
    6     "Returns a list of table names in the current database."
    7     cursor.execute("""
    8         SELECT c.relname
    9         FROM pg_catalog.pg_class c
    10         LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
    11         WHERE c.relkind IN ('r', 'v', '')
    12             AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
    13             AND pg_catalog.pg_table_is_visible(c.oid)""")
    14     return [row[0] for row in cursor.fetchall()]
     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" % self.connection.ops.quote_name(table_name))
     35        return cursor.description
    1536
    16 def get_table_description(cursor, table_name):
    17     "Returns a description of the table, with the DB-API cursor.description interface."
    18     cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name))
    19     return cursor.description
     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
    2057
    21 def get_relations(cursor, table_name):
    22     """
    23     Returns a dictionary of {field_index: (field_index_other_table, other_table)}
    24     representing all relationships to the given table. Indexes are 0-based.
    25     """
    26     cursor.execute("""
    27         SELECT con.conkey, con.confkey, c2.relname
    28         FROM pg_constraint con, pg_class c1, pg_class c2
    29         WHERE c1.oid = con.conrelid
    30             AND c2.oid = con.confrelid
    31             AND c1.relname = %s
    32             AND con.contype = 'f'""", [table_name])
    33     relations = {}
    34     for row in cursor.fetchall():
    35         try:
    36             # row[0] and row[1] are like "{2}", so strip the curly braces.
    37             relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2])
    38         except ValueError:
    39             continue
    40     return relations
     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
    4186
    42 def get_indexes(cursor, table_name):
    43     """
    44     Returns a dictionary of fieldname -> infodict for the given table,
    45     where each infodict is in the format:
    46         {'primary_key': boolean representing whether it's the primary key,
    47          'unique': boolean representing whether it's a unique index}
    48     """
    49     # This query retrieves each index on the given table, including the
    50     # first associated field name
    51     cursor.execute("""
    52         SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
    53         FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
    54             pg_catalog.pg_index idx, pg_catalog.pg_attribute attr
    55         WHERE c.oid = idx.indrelid
    56             AND idx.indexrelid = c2.oid
    57             AND attr.attrelid = c.oid
    58             AND attr.attnum = idx.indkey[0]
    59             AND c.relname = %s""", [table_name])
    60     indexes = {}
    61     for row in cursor.fetchall():
    62         # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
    63         # a string of space-separated integers. This designates the field
    64         # indexes (1-based) of the fields that have indexes on the table.
    65         # Here, we skip any indexes across multiple fields.
    66         if ' ' in row[1]:
    67             continue
    68         indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
    69     return indexes
    70 
    71 # Maps type codes to Django Field types.
    72 DATA_TYPES_REVERSE = {
    73     16: 'BooleanField',
    74     21: 'SmallIntegerField',
    75     23: 'IntegerField',
    76     25: 'TextField',
    77     701: 'FloatField',
    78     869: 'IPAddressField',
    79     1043: 'CharField',
    80     1082: 'DateField',
    81     1083: 'TimeField',
    82     1114: 'DateTimeField',
    83     1184: 'DateTimeField',
    84     1266: 'TimeField',
    85     1700: 'DecimalField',
    86 }
  • django/db/backends/postgresql/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(%(max_length)s)',
    14     'FilePathField':     'varchar(%(max_length)s)',
    15     'FloatField':        'double precision',
    16     'IntegerField':      'integer',
    17     'IPAddressField':    'inet',
    18     'NullBooleanField':  'boolean',
    19     'OneToOneField':     'integer',
    20     'PhoneNumberField':  'varchar(20)',
    21     'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)',
    22     'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)',
    23     'SlugField':         'varchar(%(max_length)s)',
    24     'SmallIntegerField': 'smallint',
    25     'TextField':         'text',
    26     'TimeField':         'time',
    27     'USStateField':      'varchar(2)',
    28 }
     1from django.conf import settings
     2from django.db.backends.creation import BaseDatabaseCreation
     3
     4class DatabaseCreation(BaseDatabaseCreation):
     5    # This dictionary maps Field objects to their associated PostgreSQL column
     6    # types, as strings. Column-type strings can contain format strings; they'll
     7    # be interpolated against the values of Field.__dict__ before being output.
     8    # If a column type is set to None, it won't be included in the output.
     9    data_types = {
     10        'AutoField':         'serial',
     11        'BooleanField':      'boolean',
     12        'CharField':         'varchar(%(max_length)s)',
     13        'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
     14        'DateField':         'date',
     15        'DateTimeField':     'timestamp with time zone',
     16        'DecimalField':      'numeric(%(max_digits)s, %(decimal_places)s)',
     17        'FileField':         'varchar(%(max_length)s)',
     18        'FilePathField':     'varchar(%(max_length)s)',
     19        'FloatField':        'double precision',
     20        'IntegerField':      'integer',
     21        'IPAddressField':    'inet',
     22        'NullBooleanField':  'boolean',
     23        'OneToOneField':     'integer',
     24        'PhoneNumberField':  'varchar(20)',
     25        'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)',
     26        'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)',
     27        'SlugField':         'varchar(%(max_length)s)',
     28        'SmallIntegerField': 'smallint',
     29        'TextField':         'text',
     30        'TimeField':         'time',
     31        'USStateField':      'varchar(2)',
     32    }
     33
     34    def _creation_suffix(self):
     35        assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time."
     36        if settings.TEST_DATABASE_CHARSET:
     37            return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET
     38        return ''
  • django/db/backends/sqlite3/base.py

     
    66Python 2.5 and later use the sqlite3 module in the standard library.
    77"""
    88
    9 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
     9from django.db.backends import BaseDatabaseWrapper
     10from django.db.backends import BaseDatabaseFeatures
     11from django.db.backends import BaseDatabaseOperations
     12from django.db.backends import BaseDatabaseValidation
     13from django.db.backends import util
     14from django.db.backends.sqlite3.client import DatabaseClient
     15from django.db.backends.sqlite3.creation import DatabaseCreation
     16from django.db.backends.sqlite3.introspection import DatabaseIntrospection
     17
    1018try:
    1119    try:
    1220        from sqlite3 import dbapi2 as Database
     
    3947Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal)
    4048
    4149class DatabaseFeatures(BaseDatabaseFeatures):
    42     supports_constraints = False
    4350    # SQLite cannot handle us only partially reading from a cursor's result set
    4451    # and then writing the same rows to the database in another cursor. This
    4552    # setting ensures we always read result sets fully into memory all in one
     
    8996        second = '%s-12-31 23:59:59.999999'
    9097        return [first % value, second % value]
    9198
     99class DatabaseValidation(BaseDatabaseValidation):
     100    pass
    92101
    93102class DatabaseWrapper(BaseDatabaseWrapper):
    94     features = DatabaseFeatures()
    95     ops = DatabaseOperations()
    96 
     103   
    97104    # SQLite requires LIKE statements to include an ESCAPE clause if the value
    98105    # being escaped has a percent or underscore in it.
    99106    # See http://www.sqlite.org/lang_expr.html for an explanation.
     
    114121        'iendswith': "LIKE %s ESCAPE '\\'",
    115122    }
    116123
     124    def __init__(self, *args, **kwargs):
     125        super(DatabaseWrapper, self).__init__(*args, **kwargs)
     126       
     127        self.features = DatabaseFeatures()
     128        self.ops = DatabaseOperations()
     129        self.client = DatabaseClient()
     130        self.creation = DatabaseCreation(self)
     131        self.introspection = DatabaseIntrospection(self)
     132        self.validation = DatabaseValidation()
     133
    117134    def _cursor(self, settings):
    118135        if self.connection is None:
    119136            if not settings.DATABASE_NAME:
  • django/db/backends/sqlite3/client.py

     
     1from django.db.backends import BaseDatabaseClient
    12from django.conf import settings
    23import os
    34
    4 def runshell():
    5     args = ['', settings.DATABASE_NAME]
    6     os.execvp('sqlite3', args)
     5class DatabaseClient(BaseDatabaseClient):
     6    def runshell(self):
     7        args = ['', settings.DATABASE_NAME]
     8        os.execvp('sqlite3', args)
  • django/db/backends/sqlite3/introspection.py

     
    1 from django.db.backends.sqlite3.base import DatabaseOperations
     1from django.db.backends import BaseDatabaseIntrospection
    22
    3 quote_name = DatabaseOperations().quote_name
    4 
    5 def get_table_list(cursor):
    6     "Returns a list of table names in the current database."
    7     # Skip the sqlite_sequence system table used for autoincrement key
    8     # generation.
    9     cursor.execute("""
    10         SELECT name FROM sqlite_master
    11         WHERE type='table' AND NOT name='sqlite_sequence'
    12         ORDER BY name""")
    13     return [row[0] for row in cursor.fetchall()]
    14 
    15 def get_table_description(cursor, table_name):
    16     "Returns a description of the table, with the DB-API cursor.description interface."
    17     return [(info['name'], info['type'], None, None, None, None,
    18              info['null_ok']) for info in _table_info(cursor, table_name)]
    19 
    20 def get_relations(cursor, table_name):
    21     raise NotImplementedError
    22 
    23 def get_indexes(cursor, table_name):
    24     """
    25     Returns a dictionary of fieldname -> infodict for the given table,
    26     where each infodict is in the format:
    27         {'primary_key': boolean representing whether it's the primary key,
    28          'unique': boolean representing whether it's a unique index}
    29     """
    30     indexes = {}
    31     for info in _table_info(cursor, table_name):
    32         indexes[info['name']] = {'primary_key': info['pk'] != 0,
    33                                  'unique': False}
    34     cursor.execute('PRAGMA index_list(%s)' % quote_name(table_name))
    35     # seq, name, unique
    36     for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]:
    37         if not unique:
    38             continue
    39         cursor.execute('PRAGMA index_info(%s)' % quote_name(index))
    40         info = cursor.fetchall()
    41         # Skip indexes across multiple fields
    42         if len(info) != 1:
    43             continue
    44         name = info[0][2] # seqno, cid, name
    45         indexes[name]['unique'] = True
    46     return indexes
    47 
    48 def _table_info(cursor, name):
    49     cursor.execute('PRAGMA table_info(%s)' % quote_name(name))
    50     # cid, name, type, notnull, dflt_value, pk
    51     return [{'name': field[1],
    52              'type': field[2],
    53              'null_ok': not field[3],
    54              'pk': field[5]     # undocumented
    55              } for field in cursor.fetchall()]
    56 
    57 # Maps SQL types to Django Field types. Some of the SQL types have multiple
    58 # entries here because SQLite allows for anything and doesn't normalize the
    59 # field type; it uses whatever was given.
    60 BASE_DATA_TYPES_REVERSE = {
    61     'bool': 'BooleanField',
    62     'boolean': 'BooleanField',
    63     'smallint': 'SmallIntegerField',
    64     'smallinteger': 'SmallIntegerField',
    65     'int': 'IntegerField',
    66     'integer': 'IntegerField',
    67     'text': 'TextField',
    68     'char': 'CharField',
    69     'date': 'DateField',
    70     'datetime': 'DateTimeField',
    71     'time': 'TimeField',
    72 }
    73 
    743# This light wrapper "fakes" a dictionary interface, because some SQLite data
    754# types include variables in them -- e.g. "varchar(30)" -- and can't be matched
    765# as a simple dictionary lookup.
    776class FlexibleFieldLookupDict:
     7    # Maps SQL types to Django Field types. Some of the SQL types have multiple
     8    # entries here because SQLite allows for anything and doesn't normalize the
     9    # field type; it uses whatever was given.
     10    base_data_types_reverse = {
     11        'bool': 'BooleanField',
     12        'boolean': 'BooleanField',
     13        'smallint': 'SmallIntegerField',
     14        'smallinteger': 'SmallIntegerField',
     15        'int': 'IntegerField',
     16        'integer': 'IntegerField',
     17        'text': 'TextField',
     18        'char': 'CharField',
     19        'date': 'DateField',
     20        'datetime': 'DateTimeField',
     21        'time': 'TimeField',
     22    }
     23
    7824    def __getitem__(self, key):
    7925        key = key.lower()
    8026        try:
    81             return BASE_DATA_TYPES_REVERSE[key]
     27            return self.base_data_types_reverse[key]
    8228        except KeyError:
    8329            import re
    8430            m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key)
     
    8632                return ('CharField', {'max_length': int(m.group(1))})
    8733            raise KeyError
    8834
    89 DATA_TYPES_REVERSE = FlexibleFieldLookupDict()
     35class DatabaseIntrospection(BaseDatabaseIntrospection):
     36    data_types_reverse = FlexibleFieldLookupDict()
     37       
     38    def get_table_list(self, cursor):
     39        "Returns a list of table names in the current database."
     40        # Skip the sqlite_sequence system table used for autoincrement key
     41        # generation.
     42        cursor.execute("""
     43            SELECT name FROM sqlite_master
     44            WHERE type='table' AND NOT name='sqlite_sequence'
     45            ORDER BY name""")
     46        return [row[0] for row in cursor.fetchall()]
     47
     48    def get_table_description(self, cursor, table_name):
     49        "Returns a description of the table, with the DB-API cursor.description interface."
     50        return [(info['name'], info['type'], None, None, None, None,
     51                 info['null_ok']) for info in self._table_info(cursor, table_name)]
     52
     53    def get_relations(self, cursor, table_name):
     54        raise NotImplementedError
     55
     56    def get_indexes(self, cursor, table_name):
     57        """
     58        Returns a dictionary of fieldname -> infodict for the given table,
     59        where each infodict is in the format:
     60            {'primary_key': boolean representing whether it's the primary key,
     61             'unique': boolean representing whether it's a unique index}
     62        """
     63        indexes = {}
     64        for info in self._table_info(cursor, table_name):
     65            indexes[info['name']] = {'primary_key': info['pk'] != 0,
     66                                     'unique': False}
     67        cursor.execute('PRAGMA index_list(%s)' % self.ops.quote_name(table_name))
     68        # seq, name, unique
     69        for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]:
     70            if not unique:
     71                continue
     72            cursor.execute('PRAGMA index_info(%s)' % self.ops.quote_name(index))
     73            info = cursor.fetchall()
     74            # Skip indexes across multiple fields
     75            if len(info) != 1:
     76                continue
     77            name = info[0][2] # seqno, cid, name
     78            indexes[name]['unique'] = True
     79        return indexes
     80
     81    def _table_info(self, cursor, name):
     82        cursor.execute('PRAGMA table_info(%s)' % self.ops.quote_name(name))
     83        # cid, name, type, notnull, dflt_value, pk
     84        return [{'name': field[1],
     85                 'type': field[2],
     86                 'null_ok': not field[3],
     87                 'pk': field[5]     # undocumented
     88                 } for field in cursor.fetchall()]
     89
  • django/db/backends/sqlite3/creation.py

     
    1 # SQLite doesn't actually support most of these types, but it "does the right
    2 # thing" given more verbose field definitions, so leave them as is so that
    3 # schema inspection is more useful.
    4 DATA_TYPES = {
    5     'AutoField':                    'integer',
    6     'BooleanField':                 'bool',
    7     'CharField':                    'varchar(%(max_length)s)',
    8     'CommaSeparatedIntegerField':   'varchar(%(max_length)s)',
    9     'DateField':                    'date',
    10     'DateTimeField':                'datetime',
    11     'DecimalField':                 'decimal',
    12     'FileField':                    'varchar(%(max_length)s)',
    13     'FilePathField':                'varchar(%(max_length)s)',
    14     'FloatField':                   'real',
    15     'IntegerField':                 'integer',
    16     'IPAddressField':               'char(15)',
    17     'NullBooleanField':             'bool',
    18     'OneToOneField':                'integer',
    19     'PhoneNumberField':             'varchar(20)',
    20     'PositiveIntegerField':         'integer unsigned',
    21     'PositiveSmallIntegerField':    'smallint unsigned',
    22     'SlugField':                    'varchar(%(max_length)s)',
    23     'SmallIntegerField':            'smallint',
    24     'TextField':                    'text',
    25     'TimeField':                    'time',
    26     'USStateField':                 'varchar(2)',
    27 }
     1import os
     2import sys
     3from django.conf import settings
     4from django.db.backends.creation import BaseDatabaseCreation
     5
     6class DatabaseCreation(BaseDatabaseCreation):
     7    # SQLite doesn't actually support most of these types, but it "does the right
     8    # thing" given more verbose field definitions, so leave them as is so that
     9    # schema inspection is more useful.
     10    data_types = {
     11        'AutoField':                    'integer',
     12        'BooleanField':                 'bool',
     13        'CharField':                    'varchar(%(max_length)s)',
     14        'CommaSeparatedIntegerField':   'varchar(%(max_length)s)',
     15        'DateField':                    'date',
     16        'DateTimeField':                'datetime',
     17        'DecimalField':                 'decimal',
     18        'FileField':                    'varchar(%(max_length)s)',
     19        'FilePathField':                'varchar(%(max_length)s)',
     20        'FloatField':                   'real',
     21        'IntegerField':                 'integer',
     22        'IPAddressField':               'char(15)',
     23        'NullBooleanField':             'bool',
     24        'OneToOneField':                'integer',
     25        'PhoneNumberField':             'varchar(20)',
     26        'PositiveIntegerField':         'integer unsigned',
     27        'PositiveSmallIntegerField':    'smallint unsigned',
     28        'SlugField':                    'varchar(%(max_length)s)',
     29        'SmallIntegerField':            'smallint',
     30        'TextField':                    'text',
     31        'TimeField':                    'time',
     32        'USStateField':                 'varchar(2)',
     33    }
     34   
     35    def sql_for_pending_references(self, model, style, pending_references):
     36        "SQLite3 doesn't support constraints"
     37        return []
     38
     39    def sql_remove_table_constraints(self, model, references_to_delete):
     40        "SQLite3 doesn't support constraints"
     41        return []
     42       
     43    def _create_test_db(self, verbosity, autoclobber):
     44        if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:":
     45            test_database_name = settings.TEST_DATABASE_NAME
     46            # Erase the old test database
     47            if verbosity >= 1:
     48                print "Destroying old test database..."
     49            if os.access(test_database_name, os.F_OK):
     50                if not autoclobber:
     51                    confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % test_database_name)
     52                if autoclobber or confirm == 'yes':
     53                  try:
     54                      if verbosity >= 1:
     55                          print "Destroying old test database..."
     56                      os.remove(test_database_name)
     57                  except Exception, e:
     58                      sys.stderr.write("Got an error deleting the old test database: %s\n" % e)
     59                      sys.exit(2)
     60                else:
     61                    print "Tests cancelled."
     62                    sys.exit(1)
     63            if verbosity >= 1:
     64                print "Creating test database..."
     65        else:
     66            test_database_name = ":memory:"
     67        return test_database_name
     68       
     69    def _destroy_test_db(self, test_database_name, verbosity):
     70        if test_database_name and test_database_name != ":memory:":
     71            # Remove the SQLite database file
     72            os.remove(test_database_name)       
     73                   
     74 No newline at end of file
  • django/db/backends/mysql/base.py

     
    44Requires MySQLdb: http://sourceforge.net/projects/mysql-python
    55"""
    66
    7 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
     7from django.db.backends import BaseDatabaseFeatures
     8from django.db.backends import BaseDatabaseOperations
     9from django.db.backends import BaseDatabaseWrapper
     10from django.db.backends import util
     11from django.db.backends.mysql.client import DatabaseClient
     12from django.db.backends.mysql.creation import DatabaseCreation
     13from django.db.backends.mysql.introspection import DatabaseIntrospection
     14from django.db.backends.mysql.validation import DatabaseValidation
     15
    816try:
    917    import MySQLdb as Database
    1018except ImportError, e:
     
    6068# TRADITIONAL will automatically cause most warnings to be treated as errors.
    6169
    6270class DatabaseFeatures(BaseDatabaseFeatures):
    63     inline_fk_references = False
    6471    empty_fetchmany_value = ()
    6572    update_can_self_select = False
    6673
     
    142149        return [first % value, second % value]
    143150
    144151class DatabaseWrapper(BaseDatabaseWrapper):
    145     features = DatabaseFeatures()
    146     ops = DatabaseOperations()
     152   
    147153    operators = {
    148154        'exact': '= BINARY %s',
    149155        'iexact': 'LIKE %s',
     
    164170    def __init__(self, **kwargs):
    165171        super(DatabaseWrapper, self).__init__(**kwargs)
    166172        self.server_version = None
     173       
     174        self.features = DatabaseFeatures()
     175        self.ops = DatabaseOperations()
     176        self.client = DatabaseClient()
     177        self.creation = DatabaseCreation(self)
     178        self.introspection = DatabaseIntrospection(self)
     179        self.validation = DatabaseValidation()
    167180
    168181    def _valid_connection(self):
    169182        if self.connection is not None:
  • django/db/backends/mysql/validation.py

     
     1from django.db.backends import BaseDatabaseValidation
     2
     3class DatabaseValidation(BaseDatabaseValidation):
     4    def validate_field(self, errors, opts, f):
     5        "Prior to MySQL 5.0.3, character fields could not exceed 255 characters"
     6        from django.db import models
     7        from django.db import connection
     8        db_version = connection.get_server_version()
     9        if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255:
     10            errors.add(opts,
     11                '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' %
     12                (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
     13   
     14 No newline at end of file
  • django/db/backends/mysql/client.py

     
     1from django.db.backends import BaseDatabaseClient
    12from django.conf import settings
    23import os
    34
    4 def runshell():
    5     args = ['']
    6     db = settings.DATABASE_OPTIONS.get('db', settings.DATABASE_NAME)
    7     user = settings.DATABASE_OPTIONS.get('user', settings.DATABASE_USER)
    8     passwd = settings.DATABASE_OPTIONS.get('passwd', settings.DATABASE_PASSWORD)
    9     host = settings.DATABASE_OPTIONS.get('host', settings.DATABASE_HOST)
    10     port = settings.DATABASE_OPTIONS.get('port', settings.DATABASE_PORT)
    11     defaults_file = settings.DATABASE_OPTIONS.get('read_default_file')
    12     # Seems to be no good way to set sql_mode with CLI
     5class DatabaseClient(BaseDatabaseClient):
     6    def runshell(self):
     7        args = ['']
     8        db = settings.DATABASE_OPTIONS.get('db', settings.DATABASE_NAME)
     9        user = settings.DATABASE_OPTIONS.get('user', settings.DATABASE_USER)
     10        passwd = settings.DATABASE_OPTIONS.get('passwd', settings.DATABASE_PASSWORD)
     11        host = settings.DATABASE_OPTIONS.get('host', settings.DATABASE_HOST)
     12        port = settings.DATABASE_OPTIONS.get('port', settings.DATABASE_PORT)
     13        defaults_file = settings.DATABASE_OPTIONS.get('read_default_file')
     14        # Seems to be no good way to set sql_mode with CLI
    1315   
    14     if defaults_file:
    15         args += ["--defaults-file=%s" % defaults_file]
    16     if user:
    17         args += ["--user=%s" % user]
    18     if passwd:
    19         args += ["--password=%s" % passwd]
    20     if host:
    21         args += ["--host=%s" % host]
    22     if port:
    23         args += ["--port=%s" % port]
    24     if db:
    25         args += [db]
     16        if defaults_file:
     17            args += ["--defaults-file=%s" % defaults_file]
     18        if user:
     19            args += ["--user=%s" % user]
     20        if passwd:
     21            args += ["--password=%s" % passwd]
     22        if host:
     23            args += ["--host=%s" % host]
     24        if port:
     25            args += ["--port=%s" % port]
     26        if db:
     27            args += [db]
    2628
    27     os.execvp('mysql', args)
     29        os.execvp('mysql', args)
  • django/db/backends/mysql/introspection.py

     
    1 from django.db.backends.mysql.base import DatabaseOperations
     1from django.db.backends import BaseDatabaseIntrospection
    22from MySQLdb import ProgrammingError, OperationalError
    33from MySQLdb.constants import FIELD_TYPE
    44import re
    55
    6 quote_name = DatabaseOperations().quote_name
    76foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
    87
    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()]
     8class DatabaseIntrospection(BaseDatabaseIntrospection):
     9    data_types_reverse = {
     10        FIELD_TYPE.BLOB: 'TextField',
     11        FIELD_TYPE.CHAR: 'CharField',
     12        FIELD_TYPE.DECIMAL: 'DecimalField',
     13        FIELD_TYPE.DATE: 'DateField',
     14        FIELD_TYPE.DATETIME: 'DateTimeField',
     15        FIELD_TYPE.DOUBLE: 'FloatField',
     16        FIELD_TYPE.FLOAT: 'FloatField',
     17        FIELD_TYPE.INT24: 'IntegerField',
     18        FIELD_TYPE.LONG: 'IntegerField',
     19        FIELD_TYPE.LONGLONG: 'IntegerField',
     20        FIELD_TYPE.SHORT: 'IntegerField',
     21        FIELD_TYPE.STRING: 'CharField',
     22        FIELD_TYPE.TIMESTAMP: 'DateTimeField',
     23        FIELD_TYPE.TINY: 'IntegerField',
     24        FIELD_TYPE.TINY_BLOB: 'TextField',
     25        FIELD_TYPE.MEDIUM_BLOB: 'TextField',
     26        FIELD_TYPE.LONG_BLOB: 'TextField',
     27        FIELD_TYPE.VAR_STRING: 'CharField',
     28    }
    1329
    14 def get_table_description(cursor, table_name):
    15     "Returns a description of the table, with the DB-API cursor.description interface."
    16     cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name))
    17     return cursor.description
     30    def get_table_list(self, cursor):
     31        "Returns a list of table names in the current database."
     32        cursor.execute("SHOW TABLES")
     33        return [row[0] for row in cursor.fetchall()]
    1834
    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))])
     35    def get_table_description(self, cursor, table_name):
     36        "Returns a description of the table, with the DB-API cursor.description interface."
     37        cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
     38        return cursor.description
    2539
    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())
     40    def _name_to_index(self, cursor, table_name):
     41        """
     42        Returns a dictionary of {field_name: field_index} for the given table.
     43        Indexes are 0-based.
     44        """
     45        return dict([(d[0], i) for i, d in enumerate(self.get_table_description(cursor, table_name))])
    5646
    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)
     47    def get_relations(self, cursor, table_name):
     48        """
     49        Returns a dictionary of {field_index: (field_index_other_table, other_table)}
     50        representing all relationships to the given table. Indexes are 0-based.
     51        """
     52        my_field_dict = self._name_to_index(cursor, table_name)
     53        constraints = []
     54        relations = {}
     55        try:
     56            # This should work for MySQL 5.0.
     57            cursor.execute("""
     58                SELECT column_name, referenced_table_name, referenced_column_name
     59                FROM information_schema.key_column_usage
     60                WHERE table_name = %s
     61                    AND table_schema = DATABASE()
     62                    AND referenced_table_name IS NOT NULL
     63                    AND referenced_column_name IS NOT NULL""", [table_name])
     64            constraints.extend(cursor.fetchall())
     65        except (ProgrammingError, OperationalError):
     66            # Fall back to "SHOW CREATE TABLE", for previous MySQL versions.
     67            # Go through all constraints and save the equal matches.
     68            cursor.execute("SHOW CREATE TABLE %s" % self.connection.ops.quote_name(table_name))
     69            for row in cursor.fetchall():
     70                pos = 0
     71                while True:
     72                    match = foreign_key_re.search(row[1], pos)
     73                    if match == None:
     74                        break
     75                    pos = match.end()
     76                    constraints.append(match.groups())
    6177
    62     return relations
     78        for my_fieldname, other_table, other_field in constraints:
     79            other_field_index = self._name_to_index(cursor, other_table)[other_field]
     80            my_field_index = my_field_dict[my_fieldname]
     81            relations[my_field_index] = (other_field_index, other_table)
    6382
    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
     83        return relations
    7684
    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 }
     85    def get_indexes(self, cursor, table_name):
     86        """
     87        Returns a dictionary of fieldname -> infodict for the given table,
     88        where each infodict is in the format:
     89            {'primary_key': boolean representing whether it's the primary key,
     90             'unique': boolean representing whether it's a unique index}
     91        """
     92        cursor.execute("SHOW INDEX FROM %s" % self.connection.ops.quote_name(table_name))
     93        indexes = {}
     94        for row in cursor.fetchall():
     95            indexes[row[4]] = {'primary_key': (row[2] == 'PRIMARY'), 'unique': not bool(row[1])}
     96        return indexes
     97
  • django/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(%(max_length)s)',
    14     'FilePathField':     'varchar(%(max_length)s)',
    15     'FloatField':        'double precision',
    16     'IntegerField':      'integer',
    17     'IPAddressField':    'char(15)',
    18     'NullBooleanField':  'bool',
    19     'OneToOneField':     'integer',
    20     'PhoneNumberField':  'varchar(20)',
    21     'PositiveIntegerField': 'integer UNSIGNED',
    22     'PositiveSmallIntegerField': 'smallint UNSIGNED',
    23     'SlugField':         'varchar(%(max_length)s)',
    24     'SmallIntegerField': 'smallint',
    25     'TextField':         'longtext',
    26     'TimeField':         'time',
    27     'USStateField':      'varchar(2)',
    28 }
     1from django.conf import settings
     2from django.db.backends.creation import BaseDatabaseCreation
     3
     4class DatabaseCreation(BaseDatabaseCreation):
     5    # This dictionary maps Field objects to their associated MySQL column
     6    # types, as strings. Column-type strings can contain format strings; they'll
     7    # be interpolated against the values of Field.__dict__ before being output.
     8    # If a column type is set to None, it won't be included in the output.
     9    data_types = {
     10        'AutoField':         'integer AUTO_INCREMENT',
     11        'BooleanField':      'bool',
     12        'CharField':         'varchar(%(max_length)s)',
     13        'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
     14        'DateField':         'date',
     15        'DateTimeField':     'datetime',
     16        'DecimalField':      'numeric(%(max_digits)s, %(decimal_places)s)',
     17        'FileField':         'varchar(%(max_length)s)',
     18        'FilePathField':     'varchar(%(max_length)s)',
     19        'FloatField':        'double precision',
     20        'IntegerField':      'integer',
     21        'IPAddressField':    'char(15)',
     22        'NullBooleanField':  'bool',
     23        'OneToOneField':     'integer',
     24        'PhoneNumberField':  'varchar(20)',
     25        'PositiveIntegerField': 'integer UNSIGNED',
     26        'PositiveSmallIntegerField': 'smallint UNSIGNED',
     27        'SlugField':         'varchar(%(max_length)s)',
     28        'SmallIntegerField': 'smallint',
     29        'TextField':         'longtext',
     30        'TimeField':         'time',
     31        'USStateField':      'varchar(2)',
     32    }
     33
     34    def _creation_suffix(self):
     35        suffix = []
     36        if settings.TEST_DATABASE_CHARSET:
     37            suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET)
     38        if settings.TEST_DATABASE_COLLATION:
     39            suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION)
     40        return ' '.join(suffix)
     41
     42    def sql_for_inline_foreign_key_references(self, field, known_models, style):
     43        "All inline references are pending under MySQL"
     44        return [], True
     45       
     46    def sql_for_inline_many_to_many_references(self, model, field, style):
     47        from django.db import models
     48        opts = model._meta
     49        qn = self.connection.ops.quote_name
     50       
     51        table_output = [
     52            '    %s %s %s,' %
     53                (style.SQL_FIELD(qn(field.m2m_column_name())),
     54                style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
     55                style.SQL_KEYWORD('NOT NULL')),
     56            '    %s %s %s,' %
     57            (style.SQL_FIELD(qn(field.m2m_reverse_name())),
     58            style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type()),
     59            style.SQL_KEYWORD('NOT NULL'))
     60        ]
     61        deferred = [
     62            (field.m2m_db_table(), field.m2m_column_name(), opts.db_table,
     63                opts.pk.column),
     64            (field.m2m_db_table(), field.m2m_reverse_name(),
     65                field.rel.to._meta.db_table, field.rel.to._meta.pk.column)
     66            ]
     67        return table_output, deferred
     68       
     69 No newline at end of file
  • django/db/backends/oracle/base.py

     
    88import datetime
    99import time
    1010
    11 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
     11from django.db.backends import BaseDatabaseFeatures
     12from django.db.backends import BaseDatabaseOperations
     13from django.db.backends import BaseDatabaseWrapper
     14from django.db.backends import BaseDatabaseValidation
     15from django.db.backends import util
    1216from django.db.backends.oracle import query
     17from django.db.backends.oracle.client import DatabaseClient
     18from django.db.backends.oracle.creation import DatabaseCreation
     19from django.db.backends.oracle.introspection import DatabaseIntrospection
    1320from django.utils.encoding import smart_str, force_unicode
    1421
    1522# Oracle takes client-side character set encoding from the environment.
     
    2431IntegrityError = Database.IntegrityError
    2532
    2633class DatabaseFeatures(BaseDatabaseFeatures):
    27     allows_group_by_ordinal = False
    2834    empty_fetchmany_value = ()
    2935    needs_datetime_string_cast = False
    30     supports_tablespaces = True
    31     uses_case_insensitive_names = True
    3236    uses_custom_query_class = True
    3337    interprets_empty_strings_as_nulls = True
    3438
     
    194198        return [first % value, second % value]
    195199
    196200
     201class DatabaseValidation(BaseDatabaseValidation):
     202    pass
    197203
    198204class DatabaseWrapper(BaseDatabaseWrapper):
    199     features = DatabaseFeatures()
    200     ops = DatabaseOperations()
     205   
    201206    operators = {
    202207        'exact': '= %s',
    203208        'iexact': '= UPPER(%s)',
     
    214219    }
    215220    oracle_version = None
    216221
     222    def __init__(self, *args, **kwargs):       
     223        super(DatabaseWrapper, self).__init__(*args, **kwargs)
     224
     225        self.features = DatabaseFeatures()
     226        self.ops = DatabaseOperations()
     227        self.client = DatabaseClient()
     228        self.creation = DatabaseCreation(self)
     229        self.introspection = DatabaseIntrospection(self)
     230        self.validation = DatabaseValidation()
     231
    217232    def _valid_connection(self):
    218233        return self.connection is not None
    219234
  • django/db/backends/oracle/client.py

     
     1from django.db.backends import BaseDatabaseClient
    12from django.conf import settings
    23import os
    34
    4 def runshell():
    5     dsn = settings.DATABASE_USER
    6     if settings.DATABASE_PASSWORD:
    7         dsn += "/%s" % settings.DATABASE_PASSWORD
    8     if settings.DATABASE_NAME:
    9         dsn += "@%s" % settings.DATABASE_NAME
    10     args = ["sqlplus", "-L", dsn]
    11     os.execvp("sqlplus", args)
     5class DatabaseClient(BaseDatabaseClient):
     6    def runshell(self):
     7        dsn = settings.DATABASE_USER
     8        if settings.DATABASE_PASSWORD:
     9            dsn += "/%s" % settings.DATABASE_PASSWORD
     10        if settings.DATABASE_NAME:
     11            dsn += "@%s" % settings.DATABASE_NAME
     12        args = ["sqlplus", "-L", dsn]
     13        os.execvp("sqlplus", args)
  • django/db/backends/oracle/introspection.py

     
    1 from django.db.backends.oracle.base import DatabaseOperations
     1from django.db.backends import BaseDatabaseIntrospection
     2import cx_Oracle
    23import re
    3 import cx_Oracle
    44
    5 quote_name = DatabaseOperations().quote_name
    65foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
    76
    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()]
     7class DatabaseIntrospection(BaseDatabaseIntrospection):
     8    # Maps type objects to Django Field types.
     9    data_types_reverse = {
     10        cx_Oracle.CLOB: 'TextField',
     11        cx_Oracle.DATETIME: 'DateTimeField',
     12        cx_Oracle.FIXED_CHAR: 'CharField',
     13        cx_Oracle.NCLOB: 'TextField',
     14        cx_Oracle.NUMBER: 'DecimalField',
     15        cx_Oracle.STRING: 'CharField',
     16        cx_Oracle.TIMESTAMP: 'DateTimeField',
     17    }
    1218
    13 def get_table_description(cursor, table_name):
    14     "Returns a description of the table, with the DB-API cursor.description interface."
    15     cursor.execute("SELECT * FROM %s WHERE ROWNUM < 2" % quote_name(table_name))
    16     return cursor.description
     19    def get_table_list(self, cursor):
     20        "Returns a list of table names in the current database."
     21        cursor.execute("SELECT TABLE_NAME FROM USER_TABLES")
     22        return [row[0].upper() for row in cursor.fetchall()]
    1723
    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    def get_table_description(self, cursor, table_name):
     25        "Returns a description of the table, with the DB-API cursor.description interface."
     26        cursor.execute("SELECT * FROM %s WHERE ROWNUM < 2" % self.connection.ops.quote_name(table_name))
     27        return cursor.description
    2428
    25 def get_relations(cursor, table_name):
    26     """
    27     Returns a dictionary of {field_index: (field_index_other_table, other_table)}
    28     representing all relationships to the given table. Indexes are 0-based.
    29     """
    30     cursor.execute("""
    31 SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1
    32 FROM   user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb,
    33        user_tab_cols ta, user_tab_cols tb
    34 WHERE  user_constraints.table_name = %s AND
    35        ta.table_name = %s AND
    36        ta.column_name = ca.column_name AND
    37        ca.table_name = %s AND
    38        user_constraints.constraint_name = ca.constraint_name AND
    39        user_constraints.r_constraint_name = cb.constraint_name AND
    40        cb.table_name = tb.table_name AND
    41        cb.column_name = tb.column_name AND
    42        ca.position = cb.position""", [table_name, table_name, table_name])
     29    def table_name_converter(self, name):
     30        "Table name comparison is case insensitive under Oracle"
     31        return name.upper()
     32       
     33    def _name_to_index(self, cursor, table_name):
     34        """
     35        Returns a dictionary of {field_name: field_index} for the given table.
     36        Indexes are 0-based.
     37        """
     38        return dict([(d[0], i) for i, d in enumerate(self.get_table_description(cursor, table_name))])
    4339
    44     relations = {}
    45     for row in cursor.fetchall():
    46         relations[row[0]] = (row[2], row[1])
    47     return relations
     40    def get_relations(self, cursor, table_name):
     41        """
     42        Returns a dictionary of {field_index: (field_index_other_table, other_table)}
     43        representing all relationships to the given table. Indexes are 0-based.
     44        """
     45        cursor.execute("""
     46    SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1
     47    FROM   user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb,
     48           user_tab_cols ta, user_tab_cols tb
     49    WHERE  user_constraints.table_name = %s AND
     50           ta.table_name = %s AND
     51           ta.column_name = ca.column_name AND
     52           ca.table_name = %s AND
     53           user_constraints.constraint_name = ca.constraint_name AND
     54           user_constraints.r_constraint_name = cb.constraint_name AND
     55           cb.table_name = tb.table_name AND
     56           cb.column_name = tb.column_name AND
     57           ca.position = cb.position""", [table_name, table_name, table_name])
    4858
    49 def get_indexes(cursor, table_name):
    50     """
    51     Returns a dictionary of fieldname -> infodict for the given table,
    52     where each infodict is in the format:
    53         {'primary_key': boolean representing whether it's the primary key,
    54          'unique': boolean representing whether it's a unique index}
    55     """
    56     # This query retrieves each index on the given table, including the
    57     # first associated field name
    58     # "We were in the nick of time; you were in great peril!"
    59     sql = """
    60 WITH primarycols AS (
    61  SELECT user_cons_columns.table_name, user_cons_columns.column_name, 1 AS PRIMARYCOL
    62  FROM   user_cons_columns, user_constraints
    63  WHERE  user_cons_columns.constraint_name = user_constraints.constraint_name AND
    64         user_constraints.constraint_type = 'P' AND
    65         user_cons_columns.table_name = %s),
    66  uniquecols AS (
    67  SELECT user_ind_columns.table_name, user_ind_columns.column_name, 1 AS UNIQUECOL
    68  FROM   user_indexes, user_ind_columns
    69  WHERE  uniqueness = 'UNIQUE' AND
    70         user_indexes.index_name = user_ind_columns.index_name AND
    71         user_ind_columns.table_name = %s)
    72 SELECT allcols.column_name, primarycols.primarycol, uniquecols.UNIQUECOL
    73 FROM   (SELECT column_name FROM primarycols UNION SELECT column_name FROM
    74 uniquecols) allcols,
    75       primarycols, uniquecols
    76 WHERE  allcols.column_name = primarycols.column_name (+) AND
    77       allcols.column_name = uniquecols.column_name (+)
    78     """
    79     cursor.execute(sql, [table_name, table_name])
    80     indexes = {}
    81     for row in cursor.fetchall():
    82         # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
    83         # a string of space-separated integers. This designates the field
    84         # indexes (1-based) of the fields that have indexes on the table.
    85         # Here, we skip any indexes across multiple fields.
    86         indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]}
    87     return indexes
     59        relations = {}
     60        for row in cursor.fetchall():
     61            relations[row[0]] = (row[2], row[1])
     62        return relations
    8863
    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 }
     64    def get_indexes(self, 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        # This query retrieves each index on the given table, including the
     72        # first associated field name
     73        # "We were in the nick of time; you were in great peril!"
     74        sql = """
     75    WITH primarycols AS (
     76     SELECT user_cons_columns.table_name, user_cons_columns.column_name, 1 AS PRIMARYCOL
     77     FROM   user_cons_columns, user_constraints
     78     WHERE  user_cons_columns.constraint_name = user_constraints.constraint_name AND
     79            user_constraints.constraint_type = 'P' AND
     80            user_cons_columns.table_name = %s),
     81     uniquecols AS (
     82     SELECT user_ind_columns.table_name, user_ind_columns.column_name, 1 AS UNIQUECOL
     83     FROM   user_indexes, user_ind_columns
     84     WHERE  uniqueness = 'UNIQUE' AND
     85            user_indexes.index_name = user_ind_columns.index_name AND
     86            user_ind_columns.table_name = %s)
     87    SELECT allcols.column_name, primarycols.primarycol, uniquecols.UNIQUECOL
     88    FROM   (SELECT column_name FROM primarycols UNION SELECT column_name FROM
     89    uniquecols) allcols,
     90          primarycols, uniquecols
     91    WHERE  allcols.column_name = primarycols.column_name (+) AND
     92          allcols.column_name = uniquecols.column_name (+)
     93        """
     94        cursor.execute(sql, [table_name, table_name])
     95        indexes = {}
     96        for row in cursor.fetchall():
     97            # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
     98            # a string of space-separated integers. This designates the field
     99            # indexes (1-based) of the fields that have indexes on the table.
     100            # Here, we skip any indexes across multiple fields.
     101            indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]}
     102        return indexes
     103
  • django/db/backends/oracle/creation.py

     
    11import sys, time
     2from django.conf import settings
    23from django.core import management
     4from django.db.backends.creation import BaseDatabaseCreation
    35
    4 # This dictionary maps Field objects to their associated Oracle column
    5 # types, as strings. Column-type strings can contain format strings; they'll
    6 # be interpolated against the values of Field.__dict__ before being output.
    7 # If a column type is set to None, it won't be included in the output.
    8 #
    9 # Any format strings starting with "qn_" are quoted before being used in the
    10 # output (the "qn_" prefix is stripped before the lookup is performed.
    11 
    12 DATA_TYPES = {
    13     'AutoField':                    'NUMBER(11)',
    14     'BooleanField':                 'NUMBER(1) CHECK (%(qn_column)s IN (0,1))',
    15     'CharField':                    'NVARCHAR2(%(max_length)s)',
    16     'CommaSeparatedIntegerField':   'VARCHAR2(%(max_length)s)',
    17     'DateField':                    'DATE',
    18     'DateTimeField':                'TIMESTAMP',
    19     'DecimalField':                 'NUMBER(%(max_digits)s, %(decimal_places)s)',
    20     'FileField':                    'NVARCHAR2(%(max_length)s)',
    21     'FilePathField':                'NVARCHAR2(%(max_length)s)',
    22     'FloatField':                   'DOUBLE PRECISION',
    23     'IntegerField':                 'NUMBER(11)',
    24     'IPAddressField':               'VARCHAR2(15)',
    25     'NullBooleanField':             'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL))',
    26     'OneToOneField':                'NUMBER(11)',
    27     'PhoneNumberField':             'VARCHAR2(20)',
    28     'PositiveIntegerField':         'NUMBER(11) CHECK (%(qn_column)s >= 0)',
    29     'PositiveSmallIntegerField':    'NUMBER(11) CHECK (%(qn_column)s >= 0)',
    30     'SlugField':                    'NVARCHAR2(50)',
    31     'SmallIntegerField':            'NUMBER(11)',
    32     'TextField':                    'NCLOB',
    33     'TimeField':                    'TIMESTAMP',
    34     'URLField':                     'VARCHAR2(%(max_length)s)',
    35     'USStateField':                 'CHAR(2)',
    36 }
    37 
    386TEST_DATABASE_PREFIX = 'test_'
    397PASSWORD = 'Im_a_lumberjack'
    40 REMEMBER = {}
    418
    42 def create_test_db(settings, connection, verbosity=1, autoclobber=False):
    43     TEST_DATABASE_NAME = _test_database_name(settings)
    44     TEST_DATABASE_USER = _test_database_user(settings)
    45     TEST_DATABASE_PASSWD = _test_database_passwd(settings)
    46     TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings)
    47     TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings)
     9class DatabaseCreation(BaseDatabaseCreation):
     10    # This dictionary maps Field objects to their associated Oracle column
     11    # types, as strings. Column-type strings can contain format strings; they'll
     12    # be interpolated against the values of Field.__dict__ before being output.
     13    # If a column type is set to None, it won't be included in the output.
     14    #
     15    # Any format strings starting with "qn_" are quoted before being used in the
     16    # output (the "qn_" prefix is stripped before the lookup is performed.
    4817
    49     parameters = {
    50         'dbname': TEST_DATABASE_NAME,
    51         'user': TEST_DATABASE_USER,
    52         'password': TEST_DATABASE_PASSWD,
    53         'tblspace': TEST_DATABASE_TBLSPACE,
    54         'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP,
    55         }
     18    data_types = {
     19        'AutoField':                    'NUMBER(11)',
     20        'BooleanField':                 'NUMBER(1) CHECK (%(qn_column)s IN (0,1))',
     21        'CharField':                    'NVARCHAR2(%(max_length)s)',
     22        'CommaSeparatedIntegerField':   'VARCHAR2(%(max_length)s)',
     23        'DateField':                    'DATE',
     24        'DateTimeField':                'TIMESTAMP',
     25        'DecimalField':                 'NUMBER(%(max_digits)s, %(decimal_places)s)',
     26        'FileField':                    'NVARCHAR2(%(max_length)s)',
     27        'FilePathField':                'NVARCHAR2(%(max_length)s)',
     28        'FloatField':                   'DOUBLE PRECISION',
     29        'IntegerField':                 'NUMBER(11)',
     30        'IPAddressField':               'VARCHAR2(15)',
     31        'NullBooleanField':             'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL))',
     32        'OneToOneField':                'NUMBER(11)',
     33        'PhoneNumberField':             'VARCHAR2(20)',
     34        'PositiveIntegerField':         'NUMBER(11) CHECK (%(qn_column)s >= 0)',
     35        'PositiveSmallIntegerField':    'NUMBER(11) CHECK (%(qn_column)s >= 0)',
     36        'SlugField':                    'NVARCHAR2(50)',
     37        'SmallIntegerField':            'NUMBER(11)',
     38        'TextField':                    'NCLOB',
     39        'TimeField':                    'TIMESTAMP',
     40        'URLField':                     'VARCHAR2(%(max_length)s)',
     41        'USStateField':                 'CHAR(2)',
     42    }
     43   
     44    def _create_test_db(self, verbosity, autoclobber):
     45        TEST_DATABASE_NAME = self._test_database_name(settings)
     46        TEST_DATABASE_USER = self._test_database_user(settings)
     47        TEST_DATABASE_PASSWD = self._test_database_passwd(settings)
     48        TEST_DATABASE_TBLSPACE = self._test_database_tblspace(settings)
     49        TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp(settings)
    5650
    57     REMEMBER['user'] = settings.DATABASE_USER
    58     REMEMBER['passwd'] = settings.DATABASE_PASSWORD
     51        parameters = {
     52            'dbname': TEST_DATABASE_NAME,
     53            'user': TEST_DATABASE_USER,
     54            'password': TEST_DATABASE_PASSWD,
     55            'tblspace': TEST_DATABASE_TBLSPACE,
     56            'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP,
     57        }
    5958
    60     cursor = connection.cursor()
    61     if _test_database_create(settings):
    62         if verbosity >= 1:
    63             print 'Creating test database...'
    64         try:
    65             _create_test_db(cursor, parameters, verbosity)
    66         except Exception, e:
    67             sys.stderr.write("Got an error creating the test database: %s\n" % e)
    68             if not autoclobber:
    69                 confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)
    70             if autoclobber or confirm == 'yes':
    71                 try:
    72                     if verbosity >= 1:
    73                         print "Destroying old test database..."
    74                     _destroy_test_db(cursor, parameters, verbosity)
    75                     if verbosity >= 1:
    76                         print "Creating test database..."
    77                     _create_test_db(cursor, parameters, verbosity)
    78                 except Exception, e:
    79                     sys.stderr.write("Got an error recreating the test database: %s\n" % e)
    80                     sys.exit(2)
    81             else:
    82                 print "Tests cancelled."
    83                 sys.exit(1)
     59        self.remember['user'] = settings.DATABASE_USER
     60        self.remember['passwd'] = settings.DATABASE_PASSWORD
    8461
    85     if _test_user_create(settings):
    86         if verbosity >= 1:
    87             print "Creating test user..."
    88         try:
    89             _create_test_user(cursor, parameters, verbosity)
    90         except Exception, e:
    91             sys.stderr.write("Got an error creating the test user: %s\n" % e)
    92             if not autoclobber:
    93                 confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER)
    94             if autoclobber or confirm == 'yes':
    95                 try:
    96                     if verbosity >= 1:
    97                         print "Destroying old test user..."
    98                     _destroy_test_user(cursor, parameters, verbosity)
    99                     if verbosity >= 1:
    100                         print "Creating test user..."
    101                     _create_test_user(cursor, parameters, verbosity)
    102                 except Exception, e:
    103                     sys.stderr.write("Got an error recreating the test user: %s\n" % e)
    104                     sys.exit(2)
    105             else:
    106                 print "Tests cancelled."
    107                 sys.exit(1)
     62        cursor = self.connection.cursor()
     63        if self._test_database_create(settings):
     64            if verbosity >= 1:
     65                print 'Creating test database...'
     66            try:
     67                self._execute_test_db_creation(cursor, parameters, verbosity)
     68            except Exception, e:
     69                sys.stderr.write("Got an error creating the test database: %s\n" % e)
     70                if not autoclobber:
     71                    confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)
     72                if autoclobber or confirm == 'yes':
     73                    try:
     74                        if verbosity >= 1:
     75                            print "Destroying old test database..."
     76                        self._execute_test_db_destruction(cursor, parameters, verbosity)
     77                        if verbosity >= 1:
     78                            print "Creating test database..."
     79                        self._execute_test_db_creation(cursor, parameters, verbosity)
     80                    except Exception, e:
     81                        sys.stderr.write("Got an error recreating the test database: %s\n" % e)
     82                        sys.exit(2)
     83                else:
     84                    print "Tests cancelled."
     85                    sys.exit(1)
    10886
    109     connection.close()
    110     settings.DATABASE_USER = TEST_DATABASE_USER
    111     settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD
     87        if self._test_user_create(settings):
     88            if verbosity >= 1:
     89                print "Creating test user..."
     90            try:
     91                self._create_test_user(cursor, parameters, verbosity)
     92            except Exception, e:
     93                sys.stderr.write("Got an error creating the test user: %s\n" % e)
     94                if not autoclobber:
     95                    confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER)
     96                if autoclobber or confirm == 'yes':
     97                    try:
     98                        if verbosity >= 1:
     99                            print "Destroying old test user..."
     100                        self._destroy_test_user(cursor, parameters, verbosity)
     101                        if verbosity >= 1:
     102                            print "Creating test user..."
     103                        self._create_test_user(cursor, parameters, verbosity)
     104                    except Exception, e:
     105                        sys.stderr.write("Got an error recreating the test user: %s\n" % e)
     106                        sys.exit(2)
     107                else:
     108                    print "Tests cancelled."
     109                    sys.exit(1)
    112110
    113     management.call_command('syncdb', verbosity=verbosity, interactive=False)
     111        settings.DATABASE_USER = TEST_DATABASE_USER
     112        settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD
    114113
    115     # Get a cursor (even though we don't need one yet). This has
    116     # the side effect of initializing the test database.
    117     cursor = connection.cursor()
     114        return TEST_DATABASE_NAME
     115       
     116    def _destroy_test_db(self, test_database_name, verbosity=1):
     117        """
     118        Destroy a test database, prompting the user for confirmation if the
     119        database already exists. Returns the name of the test database created.
     120        """
     121        TEST_DATABASE_NAME = self._test_database_name(settings)
     122        TEST_DATABASE_USER = self._test_database_user(settings)
     123        TEST_DATABASE_PASSWD = self._test_database_passwd(settings)
     124        TEST_DATABASE_TBLSPACE = self._test_database_tblspace(settings)
     125        TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp(settings)
    118126
    119 def destroy_test_db(settings, connection, old_database_name, verbosity=1):
    120     connection.close()
     127        settings.DATABASE_USER = self.remember['user']
     128        settings.DATABASE_PASSWORD = self.remember['passwd']
    121129
    122     TEST_DATABASE_NAME = _test_database_name(settings)
    123     TEST_DATABASE_USER = _test_database_user(settings)
    124     TEST_DATABASE_PASSWD = _test_database_passwd(settings)
    125     TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings)
    126     TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings)
     130        parameters = {
     131            'dbname': TEST_DATABASE_NAME,
     132            'user': TEST_DATABASE_USER,
     133            'password': TEST_DATABASE_PASSWD,
     134            'tblspace': TEST_DATABASE_TBLSPACE,
     135            'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP,
     136        }
    127137
    128     settings.DATABASE_NAME = old_database_name
    129     settings.DATABASE_USER = REMEMBER['user']
    130     settings.DATABASE_PASSWORD = REMEMBER['passwd']
     138        self.remember['user'] = settings.DATABASE_USER
     139        self.remember['passwd'] = settings.DATABASE_PASSWORD
    131140
    132     parameters = {
    133         'dbname': TEST_DATABASE_NAME,
    134         'user': TEST_DATABASE_USER,
    135         'password': TEST_DATABASE_PASSWD,
    136         'tblspace': TEST_DATABASE_TBLSPACE,
    137         'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP,
    138         }
     141        cursor = self.connection.cursor()
     142        time.sleep(1) # To avoid "database is being accessed by other users" errors.
     143        if self._test_user_create(settings):
     144            if verbosity >= 1:
     145                print 'Destroying test user...'
     146            self._destroy_test_user(cursor, parameters, verbosity)
     147        if self._test_database_create(settings):
     148            if verbosity >= 1:
     149                print 'Destroying test database tables...'
     150            self._execute_test_db_destruction(cursor, parameters, verbosity)
     151        self.connection.close()
    139152
    140     REMEMBER['user'] = settings.DATABASE_USER
    141     REMEMBER['passwd'] = settings.DATABASE_PASSWORD
     153    def _execute_test_db_creation(cursor, parameters, verbosity):
     154        if verbosity >= 2:
     155            print "_create_test_db(): dbname = %s" % parameters['dbname']
     156        statements = [
     157            """CREATE TABLESPACE %(tblspace)s
     158               DATAFILE '%(tblspace)s.dbf' SIZE 20M
     159               REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M
     160            """,
     161            """CREATE TEMPORARY TABLESPACE %(tblspace_temp)s
     162               TEMPFILE '%(tblspace_temp)s.dbf' SIZE 20M
     163               REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M
     164            """,
     165        ]
     166        _execute_statements(cursor, statements, parameters, verbosity)
    142167
    143     cursor = connection.cursor()
    144     time.sleep(1) # To avoid "database is being accessed by other users" errors.
    145     if _test_user_create(settings):
    146         if verbosity >= 1:
    147             print 'Destroying test user...'
    148         _destroy_test_user(cursor, parameters, verbosity)
    149     if _test_database_create(settings):
    150         if verbosity >= 1:
    151             print 'Destroying test database...'
    152         _destroy_test_db(cursor, parameters, verbosity)
    153     connection.close()
     168    def _create_test_user(cursor, parameters, verbosity):
     169        if verbosity >= 2:
     170            print "_create_test_user(): username = %s" % parameters['user']
     171        statements = [
     172            """CREATE USER %(user)s
     173               IDENTIFIED BY %(password)s
     174               DEFAULT TABLESPACE %(tblspace)s
     175               TEMPORARY TABLESPACE %(tblspace_temp)s
     176            """,
     177            """GRANT CONNECT, RESOURCE TO %(user)s""",
     178        ]
     179        _execute_statements(cursor, statements, parameters, verbosity)
    154180
    155 def _create_test_db(cursor, parameters, verbosity):
    156     if verbosity >= 2:
    157         print "_create_test_db(): dbname = %s" % parameters['dbname']
    158     statements = [
    159         """CREATE TABLESPACE %(tblspace)s
    160            DATAFILE '%(tblspace)s.dbf' SIZE 20M
    161            REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M
    162         """,
    163         """CREATE TEMPORARY TABLESPACE %(tblspace_temp)s
    164            TEMPFILE '%(tblspace_temp)s.dbf' SIZE 20M
    165            REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M
    166         """,
    167     ]
    168     _execute_statements(cursor, statements, parameters, verbosity)
     181    def _execute_test_db_destruction(cursor, parameters, verbosity):
     182        if verbosity >= 2:
     183            print "_execute_test_db_destruction(): dbname=%s" % parameters['dbname']
     184        statements = [
     185            'DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS',
     186            'DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS',
     187            ]
     188        _execute_statements(cursor, statements, parameters, verbosity)
    169189
    170 def _create_test_user(cursor, parameters, verbosity):
    171     if verbosity >= 2:
    172         print "_create_test_user(): username = %s" % parameters['user']
    173     statements = [
    174         """CREATE USER %(user)s
    175            IDENTIFIED BY %(password)s
    176            DEFAULT TABLESPACE %(tblspace)s
    177            TEMPORARY TABLESPACE %(tblspace_temp)s
    178         """,
    179         """GRANT CONNECT, RESOURCE TO %(user)s""",
    180     ]
    181     _execute_statements(cursor, statements, parameters, verbosity)
    182 
    183 def _destroy_test_db(cursor, parameters, verbosity):
    184     if verbosity >= 2:
    185         print "_destroy_test_db(): dbname=%s" % parameters['dbname']
    186     statements = [
    187         'DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS',
    188         'DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS',
     190    def _destroy_test_user(cursor, parameters, verbosity):
     191        if verbosity >= 2:
     192            print "_destroy_test_user(): user=%s" % parameters['user']
     193            print "Be patient.  This can take some time..."
     194        statements = [
     195            'DROP USER %(user)s CASCADE',
    189196        ]
    190     _execute_statements(cursor, statements, parameters, verbosity)
     197        _execute_statements(cursor, statements, parameters, verbosity)
    191198
    192 def _destroy_test_user(cursor, parameters, verbosity):
    193     if verbosity >= 2:
    194         print "_destroy_test_user(): user=%s" % parameters['user']
    195         print "Be patient.  This can take some time..."
    196     statements = [
    197         'DROP USER %(user)s CASCADE',
    198     ]
    199     _execute_statements(cursor, statements, parameters, verbosity)
     199    def _execute_statements(cursor, statements, parameters, verbosity):
     200        for template in statements:
     201            stmt = template % parameters
     202            if verbosity >= 2:
     203                print stmt
     204            try:
     205                cursor.execute(stmt)
     206            except Exception, err:
     207                sys.stderr.write("Failed (%s)\n" % (err))
     208                raise
    200209
    201 def _execute_statements(cursor, statements, parameters, verbosity):
    202     for template in statements:
    203         stmt = template % parameters
    204         if verbosity >= 2:
    205             print stmt
     210    def _test_database_name(settings):
     211        name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
    206212        try:
    207             cursor.execute(stmt)
    208         except Exception, err:
    209             sys.stderr.write("Failed (%s)\n" % (err))
     213            if settings.TEST_DATABASE_NAME:
     214                name = settings.TEST_DATABASE_NAME
     215        except AttributeError:
     216            pass
     217        except:
    210218            raise
     219        return name
    211220
    212 def _test_database_name(settings):
    213     name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
    214     try:
    215         if settings.TEST_DATABASE_NAME:
    216             name = settings.TEST_DATABASE_NAME
    217     except AttributeError:
    218         pass
    219     except:
    220         raise
    221     return name
     221    def _test_database_create(settings):
     222        name = True
     223        try:
     224            if settings.TEST_DATABASE_CREATE:
     225                name = True
     226            else:
     227                name = False
     228        except AttributeError:
     229            pass
     230        except:
     231            raise
     232        return name
    222233
    223 def _test_database_create(settings):
    224     name = True
    225     try:
    226         if settings.TEST_DATABASE_CREATE:
    227             name = True
    228         else:
    229             name = False
    230     except AttributeError:
    231         pass
    232     except:
    233         raise
    234     return name
     234    def _test_user_create(settings):
     235        name = True
     236        try:
     237            if settings.TEST_USER_CREATE:
     238                name = True
     239            else:
     240                name = False
     241        except AttributeError:
     242            pass
     243        except:
     244            raise
     245        return name
    235246
    236 def _test_user_create(settings):
    237     name = True
    238     try:
    239         if settings.TEST_USER_CREATE:
    240             name = True
    241         else:
    242             name = False
    243     except AttributeError:
    244         pass
    245     except:
    246         raise
    247     return name
     247    def _test_database_user(settings):
     248        name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
     249        try:
     250            if settings.TEST_DATABASE_USER:
     251                name = settings.TEST_DATABASE_USER
     252        except AttributeError:
     253            pass
     254        except:
     255            raise
     256        return name
    248257
    249 def _test_database_user(settings):
    250     name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
    251     try:
    252         if settings.TEST_DATABASE_USER:
    253             name = settings.TEST_DATABASE_USER
    254     except AttributeError:
    255         pass
    256     except:
    257         raise
    258     return name
     258    def _test_database_passwd(settings):
     259        name = PASSWORD
     260        try:
     261            if settings.TEST_DATABASE_PASSWD:
     262                name = settings.TEST_DATABASE_PASSWD
     263        except AttributeError:
     264            pass
     265        except:
     266            raise
     267        return name
    259268
    260 def _test_database_passwd(settings):
    261     name = PASSWORD
    262     try:
    263         if settings.TEST_DATABASE_PASSWD:
    264             name = settings.TEST_DATABASE_PASSWD
    265     except AttributeError:
    266         pass
    267     except:
    268         raise
    269     return name
     269    def _test_database_tblspace(settings):
     270        name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
     271        try:
     272            if settings.TEST_DATABASE_TBLSPACE:
     273                name = settings.TEST_DATABASE_TBLSPACE
     274        except AttributeError:
     275            pass
     276        except:
     277            raise
     278        return name
    270279
    271 def _test_database_tblspace(settings):
    272     name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
    273     try:
    274         if settings.TEST_DATABASE_TBLSPACE:
    275             name = settings.TEST_DATABASE_TBLSPACE
    276     except AttributeError:
    277         pass
    278     except:
    279         raise
    280     return name
    281 
    282 def _test_database_tblspace_tmp(settings):
    283     name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp'
    284     try:
    285         if settings.TEST_DATABASE_TBLSPACE_TMP:
    286             name = settings.TEST_DATABASE_TBLSPACE_TMP
    287     except AttributeError:
    288         pass
    289     except:
    290         raise
    291     return name
     280    def _test_database_tblspace_tmp(settings):
     281        name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp'
     282        try:
     283            if settings.TEST_DATABASE_TBLSPACE_TMP:
     284                name = settings.TEST_DATABASE_TBLSPACE_TMP
     285        except AttributeError:
     286            pass
     287        except:
     288            raise
     289        return name
  • django/db/backends/__init__.py

     
    4242        return util.CursorDebugWrapper(cursor, self)
    4343
    4444class BaseDatabaseFeatures(object):
    45     allows_group_by_ordinal = True
    46     inline_fk_references = True
    4745    # True if django.db.backend.utils.typecast_timestamp is used on values
    4846    # returned from dates() calls.
    4947    needs_datetime_string_cast = True
    50     supports_constraints = True
    51     supports_tablespaces = False
    52     uses_case_insensitive_names = False
    5348    uses_custom_query_class = False
    5449    empty_fetchmany_value = []
    5550    update_can_self_select = True
     
    253248        """
    254249        return "BEGIN;"
    255250
    256     def tablespace_sql(self, tablespace, inline=False):
     251    def sql_for_tablespace(self, tablespace, inline=False):
    257252        """
    258         Returns the tablespace SQL, or None if the backend doesn't use
    259         tablespaces.
     253        Returns the SQL that will be appended to tables or rows to define
     254        a tablespace. Returns '' if the backend doesn't use tablespaces.
    260255        """
    261         return None
    262 
     256        return ''
     257           
    263258    def prep_for_like_query(self, x):
    264259        """Prepares a value for use in a LIKE query."""
    265260        from django.utils.encoding import smart_unicode
     
    325320        """
    326321        return self.year_lookup_bounds(value)
    327322
     323class BaseDatabaseIntrospection(object):
     324    """
     325    This class encapsulates all backend-specific introspection utilities
     326    """
     327    data_types_reverse = {}
     328
     329    def __init__(self, connection):
     330        self.connection = connection
     331
     332    def table_name_converter(self, name):
     333        """Apply a conversion to the name for the purposes of comparison.
     334       
     335        The default table name converter is for case sensitive comparison.
     336        """
     337        return name
     338       
     339    def table_names(self):
     340        "Returns a list of names of all tables that exist in the database."
     341        cursor = self.connection.cursor()
     342        return self.get_table_list(cursor)
     343
     344    def django_table_names(self, only_existing=False):
     345        """
     346        Returns a list of all table names that have associated Django models and
     347        are in INSTALLED_APPS.
     348
     349        If only_existing is True, the resulting list will only include the tables
     350        that actually exist in the database.
     351        """
     352        from django.db import models
     353        tables = set()
     354        for app in models.get_apps():
     355            for model in models.get_models(app):
     356                tables.add(model._meta.db_table)
     357                tables.update([f.m2m_db_table() for f in model._meta.local_many_to_many])
     358        if only_existing:
     359            tables = [t for t in tables if t in self.table_names()]
     360        return tables
     361
     362    def installed_models(self, tables):
     363        "Returns a set of all models represented by the provided list of table names."
     364        from django.db import models
     365        all_models = []
     366        for app in models.get_apps():
     367            for model in models.get_models(app):
     368                all_models.append(model)
     369        return set([m for m in all_models
     370            if self.table_name_converter(m._meta.db_table) in map(self.table_name_converter, tables)
     371        ])
     372       
     373    def sequence_list(self):
     374        "Returns a list of information about all DB sequences for all models in all apps."
     375        from django.db import models
     376
     377        apps = models.get_apps()
     378        sequence_list = []
     379
     380        for app in apps:
     381            for model in models.get_models(app):
     382                for f in model._meta.local_fields:
     383                    if isinstance(f, models.AutoField):
     384                        sequence_list.append({'table': model._meta.db_table, 'column': f.column})
     385                        break # Only one AutoField is allowed per model, so don't bother continuing.
     386
     387                for f in model._meta.local_many_to_many:
     388                    sequence_list.append({'table': f.m2m_db_table(), 'column': None})
     389
     390        return sequence_list
     391       
     392       
     393class BaseDatabaseClient(object):
     394    """
     395    This class encapsualtes all backend-specific methods for opening a
     396    client shell
     397    """
     398    def runshell(self):
     399        raise NotImplementedError()
     400
     401class BaseDatabaseValidation(object):
     402    """
     403    This class encapsualtes all backend-specific model validation.
     404    """
     405    def validate_field(self, errors, opts, f):
     406        "By default, there is no backend-specific validation"
     407        pass
     408
  • django/db/backends/postgresql_psycopg2/base.py

     
    44Requires psycopg 2: http://initd.org/projects/psycopg2
    55"""
    66
    7 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures
     7from django.db.backends import BaseDatabaseFeatures
     8from django.db.backends import BaseDatabaseValidation
     9from django.db.backends import BaseDatabaseWrapper
    810from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
     11from django.db.backends.postgresql.client import DatabaseClient
     12from django.db.backends.postgresql.creation import DatabaseCreation
     13from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
     14
    915from django.utils.safestring import SafeUnicode
    1016try:
    1117    import psycopg2 as Database
     
    3036        # http://www.initd.org/tracker/psycopg/wiki/psycopg2_documentation#postgresql-status-message-and-executed-query
    3137        return cursor.query
    3238
     39class DatabaseValidation(BaseDatabaseValidation):
     40    pass
     41
    3342class DatabaseWrapper(BaseDatabaseWrapper):
    34     features = DatabaseFeatures()
    35     ops = DatabaseOperations()
    3643    operators = {
    3744        'exact': '= %s',
    3845        'iexact': 'ILIKE %s',
     
    5057        'iendswith': 'ILIKE %s',
    5158    }
    5259
     60    def __init__(self, *args, **kwargs):
     61        super(DatabaseWrapper, self).__init__(*args, **kwargs)
     62       
     63        self.features = DatabaseFeatures()
     64        self.ops = DatabaseOperations()
     65        self.client = DatabaseClient()
     66        self.creation = DatabaseCreation(self)
     67        self.introspection = DatabaseIntrospection(self)
     68        self.validation = DatabaseValidation()
     69
    5370    def _cursor(self, settings):
    5471        set_tz = False
    5572        if self.connection is None:
  • django/db/backends/postgresql_psycopg2/client.py

     
    1 from django.db.backends.postgresql.client import *
  • django/db/backends/postgresql_psycopg2/introspection.py

     
    1 from django.db.backends.postgresql_psycopg2.base import DatabaseOperations
     1from django.db.backends.postgresql.introspection import DatabaseIntrospection as PostgresDatabaseIntrospection
    22
    3 quote_name = DatabaseOperations().quote_name
     3class DatabaseIntrospection(PostgresDatabaseIntrospection):
    44
    5 def get_table_list(cursor):
    6     "Returns a list of table names in the current database."
    7     cursor.execute("""
    8         SELECT c.relname
    9         FROM pg_catalog.pg_class c
    10         LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
    11         WHERE c.relkind IN ('r', 'v', '')
    12             AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
    13             AND pg_catalog.pg_table_is_visible(c.oid)""")
    14     return [row[0] for row in cursor.fetchall()]
    15 
    16 def get_table_description(cursor, table_name):
    17     "Returns a description of the table, with the DB-API cursor.description interface."
    18     cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name))
    19     return cursor.description
    20 
    21 def get_relations(cursor, table_name):
    22     """
    23     Returns a dictionary of {field_index: (field_index_other_table, other_table)}
    24     representing all relationships to the given table. Indexes are 0-based.
    25     """
    26     cursor.execute("""
    27         SELECT con.conkey, con.confkey, c2.relname
    28         FROM pg_constraint con, pg_class c1, pg_class c2
    29         WHERE c1.oid = con.conrelid
    30             AND c2.oid = con.confrelid
    31             AND c1.relname = %s
    32             AND con.contype = 'f'""", [table_name])
    33     relations = {}
    34     for row in cursor.fetchall():
    35         # row[0] and row[1] are single-item lists, so grab the single item.
    36         relations[row[0][0] - 1] = (row[1][0] - 1, row[2])
    37     return relations
    38 
    39 def get_indexes(cursor, table_name):
    40     """
    41     Returns a dictionary of fieldname -> infodict for the given table,
    42     where each infodict is in the format:
    43         {'primary_key': boolean representing whether it's the primary key,
    44          'unique': boolean representing whether it's a unique index}
    45     """
    46     # This query retrieves each index on the given table, including the
    47     # first associated field name
    48     cursor.execute("""
    49         SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary
    50         FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
    51             pg_catalog.pg_index idx, pg_catalog.pg_attribute attr
    52         WHERE c.oid = idx.indrelid
    53             AND idx.indexrelid = c2.oid
    54             AND attr.attrelid = c.oid
    55             AND attr.attnum = idx.indkey[0]
    56             AND c.relname = %s""", [table_name])
    57     indexes = {}
    58     for row in cursor.fetchall():
    59         # row[1] (idx.indkey) is stored in the DB as an array. It comes out as
    60         # a string of space-separated integers. This designates the field
    61         # indexes (1-based) of the fields that have indexes on the table.
    62         # Here, we skip any indexes across multiple fields.
    63         if ' ' in row[1]:
    64             continue
    65         indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
    66     return indexes
    67 
    68 # Maps type codes to Django Field types.
    69 DATA_TYPES_REVERSE = {
    70     16: 'BooleanField',
    71     21: 'SmallIntegerField',
    72     23: 'IntegerField',
    73     25: 'TextField',
    74     701: 'FloatField',
    75     869: 'IPAddressField',
    76     1043: 'CharField',
    77     1082: 'DateField',
    78     1083: 'TimeField',
    79     1114: 'DateTimeField',
    80     1184: 'DateTimeField',
    81     1266: 'TimeField',
    82     1700: 'DecimalField',
    83 }
     5    def get_relations(self, cursor, table_name):
     6        """
     7        Returns a dictionary of {field_index: (field_index_other_table, other_table)}
     8        representing all relationships to the given table. Indexes are 0-based.
     9        """
     10        cursor.execute("""
     11            SELECT con.conkey, con.confkey, c2.relname
     12            FROM pg_constraint con, pg_class c1, pg_class c2
     13            WHERE c1.oid = con.conrelid
     14                AND c2.oid = con.confrelid
     15                AND c1.relname = %s
     16                AND con.contype = 'f'""", [table_name])
     17        relations = {}
     18        for row in cursor.fetchall():
     19            # row[0] and row[1] are single-item lists, so grab the single item.
     20            relations[row[0][0] - 1] = (row[1][0] - 1, row[2])
     21        return relations
  • django/db/backends/postgresql_psycopg2/creation.py

     
    1 from django.db.backends.postgresql.creation import *
  • django/db/backends/dummy/base.py

     
    88"""
    99
    1010from django.core.exceptions import ImproperlyConfigured
    11 from django.db.backends import BaseDatabaseFeatures, BaseDatabaseOperations
     11from django.db.backends import BaseDatabaseClient
     12from django.db.backends import BaseDatabaseFeatures
     13from django.db.backends import BaseDatabaseIntrospection
     14from django.db.backends import BaseDatabaseOperations
     15from django.db.backends import BaseDatabaseValidation
     16from django.db.backends.creation import BaseDatabaseCreation
    1217
    1318def complain(*args, **kwargs):
    1419    raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet."
     
    2530class DatabaseOperations(BaseDatabaseOperations):
    2631    quote_name = complain
    2732
    28 class DatabaseWrapper(object):
    29     features = BaseDatabaseFeatures()
    30     ops = DatabaseOperations()
     33class DatabaseClient(BaseDatabaseClient):
     34    runshell = complain
     35   
     36class DatabaseCreation(BaseDatabaseCreation):
     37    pass
     38   
     39class DatabaseIntrospection(BaseDatabaseIntrospection):
     40    get_table_list = complain
     41    get_table_description = complain
     42    get_relations = complain
     43    get_indexes = complain
     44
     45class DatabaseValidation(BaseDatabaseValidation):
     46    pass
     47   
     48class DatabaseWrapper(object):   
    3149    operators = {}
    3250    cursor = complain
    3351    _commit = complain
    3452    _rollback = ignore
    3553
    36     def __init__(self, **kwargs):
    37         pass
     54    def __init__(self, *args, **kwargs):
     55        super(DatabaseWrapper, self).__init__(*args, **kwargs)
    3856
     57        self.features = BaseDatabaseFeatures()
     58        self.ops = DatabaseOperations()
     59        self.client = DatabaseClient()
     60        self.creation = DatabaseCreation(self)
     61        self.introspection = DatabaseIntrospection(self)
     62        self.validation = DatabaseValidation()
     63
    3964    def close(self):
    4065        pass
  • django/db/backends/dummy/client.py

     
    1 from django.db.backends.dummy.base import complain
    2 
    3 runshell = complain
  • django/db/backends/dummy/introspection.py

     
    1 from django.db.backends.dummy.base import complain
    2 
    3 get_table_list = complain
    4 get_table_description = complain
    5 get_relations = complain
    6 get_indexes = complain
    7 
    8 DATA_TYPES_REVERSE = {}
  • django/db/backends/dummy/creation.py

     
    1 DATA_TYPES = {}
  • django/db/backends/creation.py

     
    1 class BaseCreation(object):
     1import sys
     2import time
     3
     4from django.conf import settings
     5from django.core.management import call_command
     6
     7# The prefix to put on the default database name when creating
     8# the test database.
     9TEST_DATABASE_PREFIX = 'test_'
     10
     11class BaseDatabaseCreation(object):
    212    """
    313    This class encapsulates all backend-specific differences that pertain to
    414    database *creation*, such as the column types to use for particular Django
    515    Fields.
    616    """
    7     pass
     17    data_types = {}
     18   
     19    def __init__(self, connection):
     20        self.connection = connection
     21       
     22    def sql_create_model(self, model, style, known_models=set()):
     23        """
     24        Returns the SQL required to create a single model, as a tuple of:
     25            (list_of_sql, pending_references_dict)
     26        """
     27        from django.db import models
     28
     29        opts = model._meta
     30        final_output = []
     31        table_output = []
     32        pending_references = {}
     33        qn = self.connection.ops.quote_name
     34        for f in opts.local_fields:
     35            col_type = f.db_type()
     36            tablespace = f.db_tablespace or opts.db_tablespace
     37            if col_type is None:
     38                # Skip ManyToManyFields, because they're not represented as
     39                # database columns in this table.
     40                continue
     41            # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
     42            field_output = [style.SQL_FIELD(qn(f.column)),
     43                style.SQL_COLTYPE(col_type)]
     44            field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
     45            if f.primary_key:
     46                field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
     47            elif f.unique:
     48                field_output.append(style.SQL_KEYWORD('UNIQUE'))
     49            if tablespace and f.unique:
     50                # We must specify the index tablespace inline, because we
     51                # won't be generating a CREATE INDEX statement for this field.
     52                field_output.append(self.connection.ops.tablespace_sql(tablespace, inline=True))
     53            if f.rel:
     54                ref_output, pending = self.sql_for_inline_foreign_key_references(f, known_models, style)
     55                if pending:
     56                    pr = pending_references.setdefault(f.rel.to, []).append((model, f))
     57                else:
     58                    field_output.extend(ref_output)
     59            table_output.append(' '.join(field_output))
     60        if opts.order_with_respect_to:
     61            table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
     62                style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
     63                style.SQL_KEYWORD('NULL'))
     64        for field_constraints in opts.unique_together:
     65            table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
     66                ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints]))
     67
     68        full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
     69        for i, line in enumerate(table_output): # Combine and add commas.
     70            full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
     71        full_statement.append(')')
     72        if opts.db_tablespace:
     73            full_statement.append(self.connection.ops.tablespace_sql(opts.db_tablespace))
     74        full_statement.append(';')
     75        final_output.append('\n'.join(full_statement))
     76
     77        if opts.has_auto_field:
     78            # Add any extra SQL needed to support auto-incrementing primary keys.
     79            auto_column = opts.auto_field.db_column or opts.auto_field.name
     80            autoinc_sql = self.connection.ops.autoinc_sql(opts.db_table, auto_column)
     81            if autoinc_sql:
     82                for stmt in autoinc_sql:
     83                    final_output.append(stmt)
     84
     85        return final_output, pending_references
     86       
     87    def sql_for_inline_foreign_key_references(self, field, known_models, style):
     88        "Return the SQL snippet defining the foreign key reference for a field"
     89        qn = self.connection.ops.quote_name
     90        if field.rel.to in known_models:
     91            output = [style.SQL_KEYWORD('REFERENCES') + ' ' + \
     92                style.SQL_TABLE(qn(field.rel.to._meta.db_table)) + ' (' + \
     93                style.SQL_FIELD(qn(field.rel.to._meta.get_field(field.rel.field_name).column)) + ')' +
     94                self.connection.ops.deferrable_sql()
     95            ]
     96            pending = False
     97        else:
     98            # We haven't yet created the table to which this field
     99            # is related, so save it for later.
     100            output = []
     101            pending = True
     102       
     103        return output, pending
     104       
     105    def sql_for_pending_references(self, model, style, pending_references):
     106        "Returns any ALTER TABLE statements to add constraints after the fact."
     107        from django.db.backends.util import truncate_name
     108
     109        qn = self.connection.ops.quote_name
     110        final_output = []
     111        opts = model._meta
     112        if model in pending_references:
     113            for rel_class, f in pending_references[model]:
     114                rel_opts = rel_class._meta
     115                r_table = rel_opts.db_table
     116                r_col = f.column
     117                table = opts.db_table
     118                col = opts.get_field(f.rel.field_name).column
     119                # For MySQL, r_name must be unique in the first 64 characters.
     120                # So we are careful with character usage here.
     121                r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
     122                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
     123                    (qn(r_table), truncate_name(r_name, self.connection.ops.max_name_length()),
     124                    qn(r_col), qn(table), qn(col),
     125                    self.connection.ops.deferrable_sql()))
     126            del pending_references[model]
     127        return final_output
     128   
     129    def many_to_many_sql_for_model(self, model, style):
     130        "Return the CREATE TABLE statments for all the many-to-many tables defined on a model"
     131        output = []
     132        for f in model._meta.local_many_to_many:
     133            output.extend(self.sql_for_many_to_many_field(model, f, style))
     134        return output
     135
     136    def sql_for_many_to_many_field(self, model, f, style):
     137        "Return the CREATE TABLE statements for a single m2m field"
     138        from django.db import models
     139        from django.db.backends.util import truncate_name
     140
     141        output = []
     142        if f.creates_table:
     143            opts = model._meta
     144            qn = self.connection.ops.quote_name
     145            tablespace = f.db_tablespace or opts.db_tablespace
     146            if tablespace:
     147                sql = self.connection.ops.tablespace_sql(tablespace, inline=True)
     148                if sql:
     149                    tablespace_sql = ' ' + sql
     150                else:
     151                    tablespace_sql = ''
     152            else:
     153                tablespace_sql = ''
     154            table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
     155                style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
     156            table_output.append('    %s %s %s%s,' %
     157                (style.SQL_FIELD(qn('id')),
     158                style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
     159                style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
     160                tablespace_sql))
     161
     162            deferred = []
     163            inline_output, deferred = self.sql_for_inline_many_to_many_references(model, f, style)
     164            table_output.extend(inline_output)
     165
     166            table_output.append('    %s (%s, %s)%s' %
     167                (style.SQL_KEYWORD('UNIQUE'),
     168                style.SQL_FIELD(qn(f.m2m_column_name())),
     169                style.SQL_FIELD(qn(f.m2m_reverse_name())),
     170                tablespace_sql))
     171            table_output.append(')')
     172            if opts.db_tablespace:
     173                # f.db_tablespace is only for indices, so ignore its value here.
     174                table_output.append(self.connection.ops.tablespace_sql(opts.db_tablespace))
     175            table_output.append(';')
     176            output.append('\n'.join(table_output))
     177
     178            for r_table, r_col, table, col in deferred:
     179                r_name = '%s_refs_%s_%x' % (r_col, col,
     180                        abs(hash((r_table, table))))
     181                output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %
     182                (qn(r_table),
     183                truncate_name(r_name, self.connection.ops.max_name_length()),
     184                qn(r_col), qn(table), qn(col),
     185                self.connection.ops.deferrable_sql()))
     186
     187            # Add any extra SQL needed to support auto-incrementing PKs
     188            autoinc_sql = self.connection.ops.autoinc_sql(f.m2m_db_table(), 'id')
     189            if autoinc_sql:
     190                for stmt in autoinc_sql:
     191                    output.append(stmt)
     192        return output       
     193
     194    def sql_for_inline_many_to_many_references(self, model, field, style):
     195        "Create the references to other tables required by a many-to-many table"
     196        from django.db import models
     197        opts = model._meta
     198        qn = self.connection.ops.quote_name
     199
     200        table_output = [
     201            '    %s %s %s %s (%s)%s,' %
     202                (style.SQL_FIELD(qn(field.m2m_column_name())),
     203                style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
     204                style.SQL_KEYWORD('NOT NULL REFERENCES'),
     205                style.SQL_TABLE(qn(opts.db_table)),
     206                style.SQL_FIELD(qn(opts.pk.column)),
     207                self.connection.ops.deferrable_sql()),
     208            '    %s %s %s %s (%s)%s,' %
     209                (style.SQL_FIELD(qn(field.m2m_reverse_name())),
     210                style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type()),
     211                style.SQL_KEYWORD('NOT NULL REFERENCES'),
     212                style.SQL_TABLE(qn(field.rel.to._meta.db_table)),
     213                style.SQL_FIELD(qn(field.rel.to._meta.pk.column)),
     214                self.connection.ops.deferrable_sql())
     215        ]
     216        deferred = []
     217
     218        return table_output, deferred
     219       
     220    def sql_indexes_for_model(self, model, style):
     221        "Returns the CREATE INDEX SQL statements for a single model"
     222        output = []
     223        for f in model._meta.local_fields:
     224            output.extend(self.sql_indexes_for_field(model, f, style))
     225        return output
     226       
     227    def sql_indexes_for_field(self, model, f, style):
     228        "Return the CREATE INDEX SQL statements for a single model field"
     229        if f.db_index and not f.unique:
     230            qn = self.connection.ops.quote_name
     231            tablespace = f.db_tablespace or model._meta.db_tablespace
     232            if tablespace:
     233                sql = self.connection.ops.tablespace_sql(tablespace)
     234                if sql:
     235                    tablespace_sql = ' ' + sql
     236                else:
     237                    tablespace_sql = ''
     238            else:
     239                tablespace_sql = ''
     240            output = [style.SQL_KEYWORD('CREATE INDEX') + ' ' +
     241                style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' +
     242                style.SQL_KEYWORD('ON') + ' ' +
     243                style.SQL_TABLE(qn(model._meta.db_table)) + ' ' +
     244                "(%s)" % style.SQL_FIELD(qn(f.column)) +
     245                "%s;" % tablespace_sql]
     246        else:
     247            output = []
     248        return output
     249
     250    def sql_destroy_model(self, model, references_to_delete, style):
     251        "Return the DROP TABLE and restraint dropping statements for a single model"
     252        # Drop the table now
     253        qn = self.connection.ops.quote_name
     254        output = ['%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
     255                              style.SQL_TABLE(qn(model._meta.db_table)))]
     256        if model in references_to_delete:
     257            output.extend(self.sql_remove_table_constraints(model, references_to_delete))
     258           
     259        if model._meta.has_auto_field:
     260            ds = self.connection.ops.drop_sequence_sql(model._meta.db_table)
     261            if ds:
     262                output.append(ds)
     263        return output
     264
     265    def sql_remove_table_constraints(self, model, references_to_delete):
     266        output = []
     267        for rel_class, f in references_to_delete[model]:
     268            table = rel_class._meta.db_table
     269            col = f.column
     270            r_table = model._meta.db_table
     271            r_col = model._meta.get_field(f.rel.field_name).column
     272            r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
     273            output.append('%s %s %s %s;' % \
     274                (style.SQL_KEYWORD('ALTER TABLE'),
     275                style.SQL_TABLE(qn(table)),
     276                style.SQL_KEYWORD(self.connection.ops.drop_foreignkey_sql()),
     277                style.SQL_FIELD(truncate_name(r_name, self.connection.ops.max_name_length()))))
     278        del references_to_delete[model]
     279        return output
     280       
     281    def sql_destroy_many_to_many(self, model, f, style):
     282        "Returns the DROP TABLE statements for a single m2m field"
     283        qn = self.connection.ops.quote_name
     284        output = []
     285        if f.creates_table:
     286            output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
     287                style.SQL_TABLE(qn(f.m2m_db_table()))))
     288            ds = self.connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column))
     289            if ds:
     290                output.append(ds)
     291        return output
     292       
     293    def create_test_db(self, verbosity=1, autoclobber=False):
     294        """
     295        Creates a test database, prompting the user for confirmation if the
     296        database already exists. Returns the name of the test database created.
     297        """
     298        if verbosity >= 1:
     299            print "Creating test database..."
     300           
     301        test_database_name = self._create_test_db(verbosity, autoclobber)
     302
     303        self.connection.close()
     304        settings.DATABASE_NAME = test_database_name
     305
     306        call_command('syncdb', verbosity=verbosity, interactive=False)
     307
     308        if settings.CACHE_BACKEND.startswith('db://'):
     309            cache_name = settings.CACHE_BACKEND[len('db://'):]
     310            call_command('createcachetable', cache_name)
     311
     312        # Get a cursor (even though we don't need one yet). This has
     313        # the side effect of initializing the test database.
     314        cursor = self.connection.cursor()
     315
     316        return test_database_name
     317
     318    def _create_test_db(self, verbosity, autoclobber):
     319        "Internal implementation - creates the test db tables."
     320        suffix = self._creation_suffix()
     321       
     322        if settings.TEST_DATABASE_NAME:
     323            test_database_name = settings.TEST_DATABASE_NAME
     324        else:
     325            test_database_name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
     326
     327        qn = self.connection.ops.quote_name
     328
     329        # Create the test database and connect to it. We need to autocommit
     330        # if the database supports it because PostgreSQL doesn't allow
     331        # CREATE/DROP DATABASE statements within transactions.
     332        cursor = self.connection.cursor()
     333        self._set_autocommit()
     334        try:
     335            cursor.execute("CREATE DATABASE %s %s" % (qn(test_database_name), suffix))
     336        except Exception, e:
     337            sys.stderr.write("Got an error creating the test database: %s\n" % e)
     338            if not autoclobber:
     339                confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % test_database_name)
     340            if autoclobber or confirm == 'yes':
     341                try:
     342                    if verbosity >= 1:
     343                        print "Destroying old test database..."
     344                    cursor.execute("DROP DATABASE %s" % qn(test_database_name))
     345                    if verbosity >= 1:
     346                        print "Creating test database..."
     347                    cursor.execute("CREATE DATABASE %s %s" % (qn(test_database_name), suffix))
     348                except Exception, e:
     349                    sys.stderr.write("Got an error recreating the test database: %s\n" % e)
     350                    sys.exit(2)
     351            else:
     352                print "Tests cancelled."
     353                sys.exit(1)
     354               
     355        return test_database_name
     356       
     357    def destroy_test_db(self, old_database_name, verbosity=1):
     358        """
     359        Destroy a test database, prompting the user for confirmation if the
     360        database already exists. Returns the name of the test database created.
     361        """
     362        if verbosity >= 1:
     363            print "Destroying test database..."
     364        self.connection.close()
     365        test_database_name = settings.DATABASE_NAME
     366        settings.DATABASE_NAME = old_database_name
     367       
     368        self._destroy_test_db(test_database_name, verbosity)
     369       
     370    def _destroy_test_db(self, test_database_name, verbosity):
     371        "Internal implementation - remove the test db tables."
     372        # Remove the test database to clean up after
     373        # ourselves. Connect to the previous database (not the test database)
     374        # to do so, because it's not allowed to delete a database while being
     375        # connected to it.
     376        cursor = self.connection.cursor()
     377        self._set_autocommit()
     378        time.sleep(1) # To avoid "database is being accessed by other users" errors.
     379        cursor.execute("DROP DATABASE %s" % self.connection.ops.quote_name(test_database_name))
     380        self.connection.close()
     381
     382    def _set_autocommit(self):
     383        "Make sure a connection is in autocommit mode."
     384        if hasattr(self.connection.connection, "autocommit"):
     385            if callable(self.connection.connection.autocommit):
     386                self.connection.connection.autocommit(True)
     387            else:
     388                self.connection.connection.autocommit = True
     389        elif hasattr(self.connection.connection, "set_isolation_level"):
     390            self.connection.connection.set_isolation_level(0)
     391
     392    def _creation_suffix(self):
     393        "SQL to append to the end of the test table creation statements"
     394        return ''
     395       
  • django/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_names, installed_models, sql_model_create, sql_for_pending_references, many_to_many_sql_for_model, custom_sql_for_model, sql_indexes_for_model, emit_post_sync_signal
     24        from django.core.management.sql import custom_sql_for_model, emit_post_sync_signal
    2525
    2626        verbosity = int(options.get('verbosity', 1))
    2727        interactive = options.get('interactive')
     
    5050
    5151        cursor = connection.cursor()
    5252
    53         if connection.features.uses_case_insensitive_names:
    54             table_name_converter = lambda x: x.upper()
    55         else:
    56             table_name_converter = lambda x: x
    57         # Get a list of all existing database tables, so we know what needs to
    58         # be added.
    59         tables = [table_name_converter(name) for name in table_names()]
    60 
    6153        # Get a list of already installed *models* so that references work right.
    62         seen_models = installed_models(tables)
     54        tables = connection.introspection.table_names()
     55        seen_models = connection.introspection.installed_models(tables)
    6356        created_models = set()
    6457        pending_references = {}
    6558
     
    7164                # Create the model's database table, if it doesn't already exist.
    7265                if verbosity >= 2:
    7366                    print "Processing %s.%s model" % (app_name, model._meta.object_name)
    74                 if table_name_converter(model._meta.db_table) in tables:
     67                if connection.introspection.table_name_converter(model._meta.db_table) in tables:
    7568                    continue
    76                 sql, references = sql_model_create(model, self.style, seen_models)
     69                sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
    7770                seen_models.add(model)
    7871                created_models.add(model)
    7972                for refto, refs in references.items():
    8073                    pending_references.setdefault(refto, []).extend(refs)
    8174                    if refto in seen_models:
    82                         sql.extend(sql_for_pending_references(refto, self.style, pending_references))
    83                 sql.extend(sql_for_pending_references(model, self.style, pending_references))
     75                        sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references))
     76                sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references))
    8477                if verbosity >= 1:
    8578                    print "Creating table %s" % model._meta.db_table
    8679                for statement in sql:
    8780                    cursor.execute(statement)
    88                 tables.append(table_name_converter(model._meta.db_table))
     81                tables.append(connection.introspection.table_name_converter(model._meta.db_table))
    8982
    9083        # Create the m2m tables. This must be done after all tables have been created
    9184        # to ensure that all referred tables will exist.
     
    9487            model_list = models.get_models(app)
    9588            for model in model_list:
    9689                if model in created_models:
    97                     sql = many_to_many_sql_for_model(model, self.style)
     90                    sql = connection.creation.many_to_many_sql_for_model(model, self.style)
    9891                    if sql:
    9992                        if verbosity >= 2:
    10093                            print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name)
     
    140133            app_name = app.__name__.split('.')[-2]
    141134            for model in models.get_models(app):
    142135                if model in created_models:
    143                     index_sql = sql_indexes_for_model(model, self.style)
     136                    index_sql = connection.creation.sql_indexes_for_model(model, self.style)
    144137                    if index_sql:
    145138                        if verbosity >= 1:
    146139                            print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
  • django/core/management/commands/testserver.py

     
    1818
    1919    def handle(self, *fixture_labels, **options):
    2020        from django.core.management import call_command
    21         from django.test.utils import create_test_db
     21        from django.db import connection
    2222
    2323        verbosity = int(options.get('verbosity', 1))
    2424        addrport = options.get('addrport')
    2525
    2626        # Create a test database.
    27         db_name = create_test_db(verbosity=verbosity)
     27        db_name = connection.creation.create_test_db(verbosity=verbosity)
    2828
    2929        # Import the fixture data into the test database.
    3030        call_command('loaddata', *fixture_labels, **{'verbosity': verbosity})
  • django/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.')
  • django/core/management/commands/dbshell.py

     
    66    requires_model_validation = False
    77
    88    def handle_noargs(self, **options):
    9         from django.db import runshell
    10         runshell()
     9        from django.db import connection
     10        connection.client.runshell()
  • django/core/management/validation.py

     
    6161            if f.db_index not in (None, True, False):
    6262                e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
    6363
    64             # Check that max_length <= 255 if using older MySQL versions.
    65             if settings.DATABASE_ENGINE == 'mysql':
    66                 db_version = connection.get_server_version()
    67                 if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255:
    68                     e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
     64            # Perform any backend-specific field validation.
     65            connection.validation.validate_field(e, opts, f)
    6966
    7067            # Check to see if the related field will clash with any existing
    7168            # fields, m2m fields, m2m related objects or related objects
  • django/core/management/sql.py

     
    77except NameError:
    88    from sets import Set as set   # Python 2.3 fallback
    99
    10 def table_names():
    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 set(get_introspection_module().get_table_list(cursor))
    15 
    16 def django_table_names(only_existing=False):
    17     """
    18     Returns a list of all table names that have associated Django models and
    19     are in INSTALLED_APPS.
    20 
    21     If only_existing is True, the resulting list will only include the tables
    22     that actually exist in the database.
    23     """
    24     from django.db import models
    25     tables = set()
    26     for app in models.get_apps():
    27         for model in models.get_models(app):
    28             tables.add(model._meta.db_table)
    29             tables.update([f.m2m_db_table() for f in model._meta.local_many_to_many])
    30     if only_existing:
    31         tables = [t for t in tables if t in table_names()]
    32     return tables
    33 
    34 def installed_models(table_list):
    35     "Returns a set of all models that are installed, given a list of existing table names."
    36     from django.db import connection, models
    37     all_models = []
    38     for app in models.get_apps():
    39         for model in models.get_models(app):
    40             all_models.append(model)
    41     if connection.features.uses_case_insensitive_names:
    42         converter = lambda x: x.upper()
    43     else:
    44         converter = lambda x: x
    45     return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
    46 
    47 def sequence_list():
    48     "Returns a list of information about all DB sequences for all models in all apps."
    49     from django.db import models
    50 
    51     apps = models.get_apps()
    52     sequence_list = []
    53 
    54     for app in apps:
    55         for model in models.get_models(app):
    56             for f in model._meta.local_fields:
    57                 if isinstance(f, models.AutoField):
    58                     sequence_list.append({'table': model._meta.db_table, 'column': f.column})
    59                     break # Only one AutoField is allowed per model, so don't bother continuing.
    60 
    61             for f in model._meta.local_many_to_many:
    62                 sequence_list.append({'table': f.m2m_db_table(), 'column': None})
    63 
    64     return sequence_list
    65 
    6610def sql_create(app, style):
    6711    "Returns a list of the CREATE TABLE SQL statements for the given app."
    68     from django.db import models
     12    from django.db import connection, models
    6913    from django.conf import settings
    7014
    7115    if settings.DATABASE_ENGINE == 'dummy':
     
    8125    # we can be conservative).
    8226    app_models = models.get_models(app)
    8327    final_output = []
    84     known_models = set([model for model in installed_models(table_names()) if model not in app_models])
     28    tables = connection.introspection.table_names()
     29    known_models = set([model for model in connection.introspection.installed_models(tables) if model not in app_models])
    8530    pending_references = {}
    8631
    8732    for model in app_models:
    88         output, references = sql_model_create(model, style, known_models)
     33        output, references = connection.creation.sql_create_model(model, style, known_models)
    8934        final_output.extend(output)
    9035        for refto, refs in references.items():
    9136            pending_references.setdefault(refto, []).extend(refs)
    9237            if refto in known_models:
    93                 final_output.extend(sql_for_pending_references(refto, style, pending_references))
    94         final_output.extend(sql_for_pending_references(model, style, pending_references))
     38                final_output.extend(connection.creation.sql_for_pending_references(refto, style, pending_references))
     39        final_output.extend(connection.creation.sql_for_pending_references(model, style, pending_references))
    9540        # Keep track of the fact that we've created the table for this model.
    9641        known_models.add(model)
    9742
    9843    # Create the many-to-many join tables.
    9944    for model in app_models:
    100         final_output.extend(many_to_many_sql_for_model(model, style))
     45        final_output.extend(connection.creation.many_to_many_sql_for_model(model, style))
    10146
    10247    # Handle references to tables that are from other apps
    10348    # but don't exist physically.
     
    10651        alter_sql = []
    10752        for model in not_installed_models:
    10853            alter_sql.extend(['-- ' + sql for sql in
    109                 sql_for_pending_references(model, style, pending_references)])
     54                connection.creation.sql_for_pending_references(model, style, pending_references)])
    11055        if alter_sql:
    11156            final_output.append('-- The following references should be added but depend on non-existent tables:')
    11257            final_output.extend(alter_sql)
     
    11560
    11661def sql_delete(app, style):
    11762    "Returns a list of the DROP TABLE SQL statements for the given app."
    118     from django.db import connection, models, get_introspection_module
     63    from django.db import connection, models
    11964    from django.db.backends.util import truncate_name
    12065    from django.contrib.contenttypes import generic
    121     introspection = get_introspection_module()
    12266
    12367    # This should work even if a connection isn't available
    12468    try:
     
    12872
    12973    # Figure out which tables already exist
    13074    if cursor:
    131         table_names = introspection.get_table_list(cursor)
     75        table_names = connection.introspection.get_table_list(cursor)
    13276    else:
    13377        table_names = []
    134     if connection.features.uses_case_insensitive_names:
    135         table_name_converter = lambda x: x.upper()
    136     else:
    137         table_name_converter = lambda x: x
    13878
    13979    output = []
    140     qn = connection.ops.quote_name
    14180
    14281    # Output DROP TABLE statements for standard application tables.
    14382    to_delete = set()
     
    14584    references_to_delete = {}
    14685    app_models = models.get_models(app)
    14786    for model in app_models:
    148         if cursor and table_name_converter(model._meta.db_table) in table_names:
     87        if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
    14988            # The table exists, so it needs to be dropped
    15089            opts = model._meta
    15190            for f in opts.local_fields:
     
    15594            to_delete.add(model)
    15695
    15796    for model in app_models:
    158         if cursor and table_name_converter(model._meta.db_table) in table_names:
    159             # Drop the table now
    160             output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
    161                 style.SQL_TABLE(qn(model._meta.db_table))))
    162             if connection.features.supports_constraints and model in references_to_delete:
    163                 for rel_class, f in references_to_delete[model]:
    164                     table = rel_class._meta.db_table
    165                     col = f.column
    166                     r_table = model._meta.db_table
    167                     r_col = model._meta.get_field(f.rel.field_name).column
    168                     r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
    169                     output.append('%s %s %s %s;' % \
    170                         (style.SQL_KEYWORD('ALTER TABLE'),
    171                         style.SQL_TABLE(qn(table)),
    172                         style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
    173                         style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
    174                 del references_to_delete[model]
    175             if model._meta.has_auto_field:
    176                 ds = connection.ops.drop_sequence_sql(model._meta.db_table)
    177                 if ds:
    178                     output.append(ds)
     97        if connection.introspection.table_name_converter(model._meta.db_table) in table_names:
     98            output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style))
    17999
    180100    # Output DROP TABLE statements for many-to-many tables.
    181101    for model in app_models:
    182102        opts = model._meta
    183103        for f in opts.local_many_to_many:
    184             if not f.creates_table:
    185                 continue
    186             if cursor and table_name_converter(f.m2m_db_table()) in table_names:
    187                 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
    188                     style.SQL_TABLE(qn(f.m2m_db_table()))))
    189                 ds = connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column))
    190                 if ds:
    191                     output.append(ds)
     104            if cursor and connection.introspection.table_name_converter(f.m2m_db_table()) in table_names:
     105                output.extend(connection.creation.sql_destroy_many_to_many(model, f, style))
    192106
    193107    app_label = app_models[0]._meta.app_label
    194108
     
    213127    """
    214128    from django.db import connection
    215129    if only_django:
    216         tables = django_table_names()
     130        tables = connection.introspection.django_table_names()
    217131    else:
    218         tables = table_names()
    219     statements = connection.ops.sql_flush(style, tables, sequence_list())
     132        tables = connection.introspection.table_names()
     133    statements = connection.ops.sql_flush(style, tables, connection.introspection.sequence_list())
    220134    return statements
    221135
    222136def sql_custom(app, style):
     
    234148
    235149def sql_indexes(app, style):
    236150    "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
    237     from django.db import models
     151    from django.db import connection, models
    238152    output = []
    239153    for model in models.get_models(app):
    240         output.extend(sql_indexes_for_model(model, style))
     154        output.extend(connection.creation.sql_indexes_for_model(model, style))
    241155    return output
    242156
    243157def sql_all(app, style):
    244158    "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
    245159    return sql_create(app, style) + sql_custom(app, style) + sql_indexes(app, style)
    246160
    247 def sql_model_create(model, style, known_models=set()):
    248     """
    249     Returns the SQL required to create a single model, as a tuple of:
    250         (list_of_sql, pending_references_dict)
    251     """
    252     from django.db import connection, models
    253 
    254     opts = model._meta
    255     final_output = []
    256     table_output = []
    257     pending_references = {}
    258     qn = connection.ops.quote_name
    259     inline_references = connection.features.inline_fk_references
    260     for f in opts.local_fields:
    261         col_type = f.db_type()
    262         tablespace = f.db_tablespace or opts.db_tablespace
    263         if col_type is None:
    264             # Skip ManyToManyFields, because they're not represented as
    265             # database columns in this table.
    266             continue
    267         # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
    268         field_output = [style.SQL_FIELD(qn(f.column)),
    269             style.SQL_COLTYPE(col_type)]
    270         field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
    271         if f.primary_key:
    272             field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
    273         elif f.unique:
    274             field_output.append(style.SQL_KEYWORD('UNIQUE'))
    275         if tablespace and connection.features.supports_tablespaces and f.unique:
    276             # We must specify the index tablespace inline, because we
    277             # won't be generating a CREATE INDEX statement for this field.
    278             field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))
    279         if f.rel:
    280             if inline_references and f.rel.to in known_models:
    281                 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
    282                     style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \
    283                     style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
    284                     connection.ops.deferrable_sql()
    285                 )
    286             else:
    287                 # We haven't yet created the table to which this field
    288                 # is related, so save it for later.
    289                 pr = pending_references.setdefault(f.rel.to, []).append((model, f))
    290         table_output.append(' '.join(field_output))
    291     if opts.order_with_respect_to:
    292         table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
    293             style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
    294             style.SQL_KEYWORD('NULL'))
    295     for field_constraints in opts.unique_together:
    296         table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
    297             ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints]))
    298 
    299     full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
    300     for i, line in enumerate(table_output): # Combine and add commas.
    301         full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
    302     full_statement.append(')')
    303     if opts.db_tablespace and connection.features.supports_tablespaces:
    304         full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
    305     full_statement.append(';')
    306     final_output.append('\n'.join(full_statement))
    307 
    308     if opts.has_auto_field:
    309         # Add any extra SQL needed to support auto-incrementing primary keys.
    310         auto_column = opts.auto_field.db_column or opts.auto_field.name
    311         autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)
    312         if autoinc_sql:
    313             for stmt in autoinc_sql:
    314                 final_output.append(stmt)
    315 
    316     return final_output, pending_references
    317 
    318 def sql_for_pending_references(model, style, pending_references):
    319     """
    320     Returns any ALTER TABLE statements to add constraints after the fact.
    321     """
    322     from django.db import connection
    323     from django.db.backends.util import truncate_name
    324 
    325     qn = connection.ops.quote_name
    326     final_output = []
    327     if connection.features.supports_constraints:
    328         opts = model._meta
    329         if model in pending_references:
    330             for rel_class, f in pending_references[model]:
    331                 rel_opts = rel_class._meta
    332                 r_table = rel_opts.db_table
    333                 r_col = f.column
    334                 table = opts.db_table
    335                 col = opts.get_field(f.rel.field_name).column
    336                 # For MySQL, r_name must be unique in the first 64 characters.
    337                 # So we are careful with character usage here.
    338                 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
    339                 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
    340                     (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
    341                     qn(r_col), qn(table), qn(col),
    342                     connection.ops.deferrable_sql()))
    343             del pending_references[model]
    344     return final_output
    345 
    346 def many_to_many_sql_for_model(model, style):
    347     from django.db import connection, models
    348     from django.contrib.contenttypes import generic
    349     from django.db.backends.util import truncate_name
    350 
    351     opts = model._meta
    352     final_output = []
    353     qn = connection.ops.quote_name
    354     inline_references = connection.features.inline_fk_references
    355     for f in opts.local_many_to_many:
    356         if f.creates_table:
    357             tablespace = f.db_tablespace or opts.db_tablespace
    358             if tablespace and connection.features.supports_tablespaces:
    359                 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace, inline=True)
    360             else:
    361                 tablespace_sql = ''
    362             table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
    363                 style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
    364             table_output.append('    %s %s %s%s,' %
    365                 (style.SQL_FIELD(qn('id')),
    366                 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
    367                 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
    368                 tablespace_sql))
    369             if inline_references:
    370                 deferred = []
    371                 table_output.append('    %s %s %s %s (%s)%s,' %
    372                     (style.SQL_FIELD(qn(f.m2m_column_name())),
    373                     style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
    374                     style.SQL_KEYWORD('NOT NULL REFERENCES'),
    375                     style.SQL_TABLE(qn(opts.db_table)),
    376                     style.SQL_FIELD(qn(opts.pk.column)),
    377                     connection.ops.deferrable_sql()))
    378                 table_output.append('    %s %s %s %s (%s)%s,' %
    379                     (style.SQL_FIELD(qn(f.m2m_reverse_name())),
    380                     style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
    381                     style.SQL_KEYWORD('NOT NULL REFERENCES'),
    382                     style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
    383                     style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
    384                     connection.ops.deferrable_sql()))
    385             else:
    386                 table_output.append('    %s %s %s,' %
    387                     (style.SQL_FIELD(qn(f.m2m_column_name())),
    388                     style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
    389                     style.SQL_KEYWORD('NOT NULL')))
    390                 table_output.append('    %s %s %s,' %
    391                     (style.SQL_FIELD(qn(f.m2m_reverse_name())),
    392                     style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
    393                     style.SQL_KEYWORD('NOT NULL')))
    394                 deferred = [
    395                     (f.m2m_db_table(), f.m2m_column_name(), opts.db_table,
    396                         opts.pk.column),
    397                     ( f.m2m_db_table(), f.m2m_reverse_name(),
    398                         f.rel.to._meta.db_table, f.rel.to._meta.pk.column)
    399                     ]
    400             table_output.append('    %s (%s, %s)%s' %
    401                 (style.SQL_KEYWORD('UNIQUE'),
    402                 style.SQL_FIELD(qn(f.m2m_column_name())),
    403                 style.SQL_FIELD(qn(f.m2m_reverse_name())),
    404                 tablespace_sql))
    405             table_output.append(')')
    406             if opts.db_tablespace and connection.features.supports_tablespaces:
    407                 # f.db_tablespace is only for indices, so ignore its value here.
    408                 table_output.append(connection.ops.tablespace_sql(opts.db_tablespace))
    409             table_output.append(';')
    410             final_output.append('\n'.join(table_output))
    411 
    412             for r_table, r_col, table, col in deferred:
    413                 r_name = '%s_refs_%s_%x' % (r_col, col,
    414                         abs(hash((r_table, table))))
    415                 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %
    416                 (qn(r_table),
    417                 truncate_name(r_name, connection.ops.max_name_length()),
    418                 qn(r_col), qn(table), qn(col),
    419                 connection.ops.deferrable_sql()))
    420 
    421             # Add any extra SQL needed to support auto-incrementing PKs
    422             autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table(), 'id')
    423             if autoinc_sql:
    424                 for stmt in autoinc_sql:
    425                     final_output.append(stmt)
    426 
    427     return final_output
    428 
    429161def custom_sql_for_model(model, style):
    430162    from django.db import models
    431163    from django.conf import settings
     
    461193
    462194    return output
    463195
    464 def sql_indexes_for_model(model, style):
    465     "Returns the CREATE INDEX SQL statements for a single model"
    466     from django.db import connection
    467     output = []
    468196
    469     qn = connection.ops.quote_name
    470     for f in model._meta.local_fields:
    471         if f.db_index and not f.unique:
    472             tablespace = f.db_tablespace or model._meta.db_tablespace
    473             if tablespace and connection.features.supports_tablespaces:
    474                 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
    475             else:
    476                 tablespace_sql = ''
    477             output.append(
    478                 style.SQL_KEYWORD('CREATE INDEX') + ' ' + \
    479                 style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
    480                 style.SQL_KEYWORD('ON') + ' ' + \
    481                 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
    482                 "(%s)" % style.SQL_FIELD(qn(f.column)) + \
    483                 "%s;" % tablespace_sql
    484             )
    485     return output
    486 
    487197def emit_post_sync_signal(created_models, verbosity, interactive):
    488198    from django.db import models
    489199    from django.dispatch import dispatcher
  • django/contrib/gis/db/backend/postgis/creation.py

     
    11from django.conf import settings
    22from django.core.management import call_command
    33from django.db import connection
    4 from django.test.utils import _set_autocommit, TEST_DATABASE_PREFIX
     4from django.db.backends.creation import TEST_DATABASE_PREFIX
    55import os, re, sys
    66
    77def getstatusoutput(cmd):
     
    3838    create_sql = 'CREATE DATABASE %s' % connection.ops.quote_name(db_name)
    3939    if settings.DATABASE_USER:
    4040        create_sql += ' OWNER %s' % settings.DATABASE_USER
    41        
     41
    4242    cursor = connection.cursor()
    43     _set_autocommit(connection)
     43    connection.creation._set_autocommit(connection)
    4444
    4545    try:
    4646        # Trying to create the database first.
     
    5858        else:
    5959            raise Exception('Spatial Database Creation canceled.')
    6060foo = _create_with_cursor
    61    
     61
    6262created_regex = re.compile(r'^createdb: database creation failed: ERROR:  database ".+" already exists')
    6363def _create_with_shell(db_name, verbosity=1, autoclobber=False):
    6464    """
    65     If no spatial database already exists, then using a cursor will not work. 
    66      Thus, a `createdb` command will be issued through the shell to bootstrap 
     65    If no spatial database already exists, then using a cursor will not work.
     66     Thus, a `createdb` command will be issued through the shell to bootstrap
    6767     creation of the spatial database.
    6868    """
    6969
     
    8383                if verbosity >= 1: print 'Destroying old spatial database...'
    8484                drop_cmd = 'dropdb %s%s' % (options, db_name)
    8585                status, output = getstatusoutput(drop_cmd)
    86                 if status != 0: 
     86                if status != 0:
    8787                    raise Exception('Could not drop database %s: %s' % (db_name, output))
    8888                if verbosity >= 1: print 'Creating new spatial database...'
    8989                status, output = getstatusoutput(create_cmd)
     
    102102        raise Exception('Spatial database creation only supported postgresql_psycopg2 platform.')
    103103
    104104    # Getting the spatial database name
    105     if test: 
     105    if test:
    106106        db_name = get_spatial_db(test=True)
    107107        _create_with_cursor(db_name, verbosity=verbosity, autoclobber=autoclobber)
    108     else: 
     108    else:
    109109        db_name = get_spatial_db()
    110110        _create_with_shell(db_name, verbosity=verbosity, autoclobber=autoclobber)
    111111
     
    125125
    126126    # Syncing the database
    127127    call_command('syncdb', verbosity=verbosity, interactive=interactive)
    128    
     128
    129129def drop_db(db_name=False, test=False):
    130130    """
    131131    Drops the given database (defaults to what is returned from
     
    151151
    152152def get_spatial_db(test=False):
    153153    """
    154     Returns the name of the spatial database.  The 'test' keyword may be set 
     154    Returns the name of the spatial database.  The 'test' keyword may be set
    155155     to return the test spatial database name.
    156156    """
    157157    if test:
     
    167167
    168168def load_postgis_sql(db_name, verbosity=1):
    169169    """
    170     This routine loads up the PostGIS SQL files lwpostgis.sql and 
     170    This routine loads up the PostGIS SQL files lwpostgis.sql and
    171171     spatial_ref_sys.sql.
    172172    """
    173173
    174174    # Getting the path to the PostGIS SQL
    175175    try:
    176         # POSTGIS_SQL_PATH may be placed in settings to tell GeoDjango where the 
     176        # POSTGIS_SQL_PATH may be placed in settings to tell GeoDjango where the
    177177        #  PostGIS SQL files are located.  This is especially useful on Win32
    178178        #  platforms since the output of pg_config looks like "C:/PROGRA~1/..".
    179179        sql_path = settings.POSTGIS_SQL_PATH
     
    193193    # Getting the psql command-line options, and command format.
    194194    options = get_cmd_options(db_name)
    195195    cmd_fmt = 'psql %s-f "%%s"' % options
    196    
     196
    197197    # Now trying to load up the PostGIS functions
    198198    cmd = cmd_fmt % lwpostgis_file
    199199    if verbosity >= 1: print cmd
     
    211211    # Setting the permissions because on Windows platforms the owner
    212212    #  of the spatial_ref_sys and geometry_columns tables is always
    213213    #  the postgres user, regardless of how the db is created.
    214     if os.name == 'nt': set_permissions(db_name) 
    215    
     214    if os.name == 'nt': set_permissions(db_name)
     215
    216216def set_permissions(db_name):
    217217    """
    218218    Sets the permissions on the given database to that of the user specified
  • django/contrib/gis/management/commands/inspectdb.py

     
    77from django.contrib.gis.db.backend import SpatialBackend
    88
    99class Command(InspectCommand):
    10    
     10
    1111    # Mapping from lower-case OGC type to the corresponding GeoDjango field.
    1212    geofield_mapping = {'point' : 'PointField',
    1313                        'linestring' : 'LineStringField',
     
    2121
    2222    def geometry_columns(self):
    2323        """
    24         Returns a datastructure of metadata information associated with the 
     24        Returns a datastructure of metadata information associated with the
    2525        `geometry_columns` (or equivalent) table.
    2626        """
    2727        # The `geo_cols` is a dictionary data structure that holds information
    28         # about any geographic columns in the database. 
     28        # about any geographic columns in the database.
    2929        geo_cols = {}
    3030        def add_col(table, column, coldata):
    3131            if table in geo_cols:
     
    4747        elif SpatialBackend.name == 'mysql':
    4848            # On MySQL have to get all table metadata before hand; this means walking through
    4949            # each table and seeing if any column types are spatial.  Can't detect this with
    50             # `cursor.description` (what the introspection module does) because all spatial types 
     50            # `cursor.description` (what the introspection module does) because all spatial types
    5151            # have the same integer type (255 for GEOMETRY).
    5252            from django.db import connection
    5353            cursor = connection.cursor()
     
    6767
    6868    def handle_inspection(self):
    6969        "Overloaded from Django's version to handle geographic database tables."
    70         from django.db import connection, get_introspection_module
     70        from django.db import connection
    7171        import keyword
    7272
    73         introspection_module = get_introspection_module()
    74 
    7573        geo_cols = self.geometry_columns()
    76        
     74
    7775        table2model = lambda table_name: table_name.title().replace('_', '')
    7876
    7977        cursor = connection.cursor()
     
    8886        yield ''
    8987        yield 'from django.contrib.gis.db import models'
    9088        yield ''
    91         for table_name in introspection_module.get_table_list(cursor):
     89        for table_name in connection.introspection.get_table_list(cursor):
    9290            # Getting the geographic table dictionary.
    9391            geo_table = geo_cols.get(table_name, {})
    9492
    9593            yield 'class %s(models.Model):' % table2model(table_name)
    9694            try:
    97                 relations = introspection_module.get_relations(cursor, table_name)
     95                relations = connection.introspection.get_relations(cursor, table_name)
    9896            except NotImplementedError:
    9997                relations = {}
    10098            try:
    101                 indexes = introspection_module.get_indexes(cursor, table_name)
     99                indexes = connection.introspection.get_indexes(cursor, table_name)
    102100            except NotImplementedError:
    103101                indexes = {}
    104             for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)):
     102            for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)):
    105103                att_name, iatt_name = row[0].lower(), row[0]
    106104                comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
    107105                extra_params = {}  # Holds Field parameters such as 'db_column'.
     
    133131                        if srid != 4326: extra_params['srid'] = srid
    134132                    else:
    135133                        try:
    136                             field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]
     134                            field_type = connection.introspection.data_types_reverse[row[1]]
    137135                        except KeyError:
    138136                            field_type = 'TextField'
    139137                            comment_notes.append('This field type is a guess.')
    140138
    141                     # This is a hook for DATA_TYPES_REVERSE to return a tuple of
     139                    # This is a hook for data_types_reverse to return a tuple of
    142140                    # (field_type, extra_params_dict).
    143141                    if type(field_type) is tuple:
    144142                        field_type, new_params = field_type
  • tests/regressiontests/backends/models.py

     
    1515    def __unicode__(self):
    1616        return u'%s %s' % (self.first_name, self.last_name)
    1717
    18 if connection.features.uses_case_insensitive_names:
    19     t_convert = lambda x: x.upper()
    20 else:
    21     t_convert = lambda x: x
    2218qn = connection.ops.quote_name
    2319
    2420__test__ = {'API_TESTS': """
     
    2925>>> opts = Square._meta
    3026>>> f1, f2 = opts.get_field('root'), opts.get_field('square')
    3127>>> query = ('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)'
    32 ...         % (t_convert(opts.db_table), qn(f1.column), qn(f2.column)))
     28...         % (connection.introspection.table_name_converter(opts.db_table), qn(f1.column), qn(f2.column)))
    3329>>> cursor.executemany(query, [(i, i**2) for i in range(-5, 6)]) and None or None
    3430>>> Square.objects.order_by('root')
    3531[<Square: -5 ** 2 == 25>, <Square: -4 ** 2 == 16>, <Square: -3 ** 2 == 9>, <Square: -2 ** 2 == 4>, <Square: -1 ** 2 == 1>, <Square: 0 ** 2 == 0>, <Square: 1 ** 2 == 1>, <Square: 2 ** 2 == 4>, <Square: 3 ** 2 == 9>, <Square: 4 ** 2 == 16>, <Square: 5 ** 2 == 25>]
     
    4844>>> opts2 = Person._meta
    4945>>> f3, f4 = opts2.get_field('first_name'), opts2.get_field('last_name')
    5046>>> query2 = ('SELECT %s, %s FROM %s ORDER BY %s'
    51 ...          % (qn(f3.column), qn(f4.column), t_convert(opts2.db_table),
     47...          % (qn(f3.column), qn(f4.column), connection.introspection.table_name_converter(opts2.db_table),
    5248...             qn(f3.column)))
    5349>>> cursor.execute(query2) and None or None
    5450>>> cursor.fetchone()
  • docs/testing.txt

     
    10261026    black magic hooks into the template system and restoring normal e-mail
    10271027    services.
    10281028
     1029The creation module of the database backend (``connection.creation``) also
     1030provides some utilities that can be useful during testing.
     1031
    10291032``create_test_db(verbosity=1, autoclobber=False)``
    10301033    Creates a new test database and runs ``syncdb`` against it.
    10311034
Back to Top