Django

Code

Ticket #5461: 5461-r8280.diff

File 5461-r8280.diff, 167.4 kB (added by russellm, 5 months ago)

rc3 for Creation backend patch - minor style changes, and some GIS fixes.

  • django/test/simple.py

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    44Requires psycopg 1: http://initd.org/projects/psycopg1 
    55""" 
    66 
     7from django.db.backends import * 
     8from django.db.backends.postgresql.client import DatabaseClient 
     9from django.db.backends.postgresql.creation import DatabaseCreation 
     10from django.db.backends.postgresql.introspection import DatabaseIntrospection 
     11from django.db.backends.postgresql.operations import DatabaseOperations 
    712from 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 
     13 
    1014try: 
    1115    import psycopg as Database 
    1216except ImportError, e: 
     
    5963    def __iter__(self): 
    6064        return iter(self.cursor) 
    6165 
    62 class DatabaseFeatures(BaseDatabaseFeatures): 
    63     pass # This backend uses all the defaults. 
    64  
    6566class DatabaseWrapper(BaseDatabaseWrapper): 
    66     features = DatabaseFeatures() 
    67     ops = DatabaseOperations() 
    6867    operators = { 
    6968        'exact': '= %s', 
    7069        'iexact': 'ILIKE %s', 
     
    8281        'iendswith': 'ILIKE %s', 
    8382    } 
    8483 
     84    def __init__(self, *args, **kwargs): 
     85        super(DatabaseWrapper, self).__init__(*args, **kwargs) 
     86         
     87        self.features = BaseDatabaseFeatures() 
     88        self.ops = DatabaseOperations() 
     89        self.client = DatabaseClient() 
     90        self.creation = DatabaseCreation(self) 
     91        self.introspection = DatabaseIntrospection(self) 
     92        self.validation = BaseDatabaseValidation() 
     93 
    8594    def _cursor(self, settings): 
    8695        set_tz = False 
    8796        if self.connection is None: 
  • django/db/backends/postgresql/client.py

    old new  
     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

    old new  
    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

    old new  
    1 # This dictionary maps Field objects to their associated PostgreSQL column 
    2 # types, as strings. Column-type strings can contain format strings; they'll 
    3 # be interpolated against the values of Field.__dict__ before being output. 
    4 # If a column type is set to None, it won't be included in the output. 
    5 DATA_TYPES = { 
    6     'AutoField':         'serial', 
    7     'BooleanField':      'boolean', 
    8     'CharField':         'varchar(%(max_length)s)', 
    9     'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 
    10     'DateField':         'date', 
    11     'DateTimeField':     'timestamp with time zone', 
    12     'DecimalField':      'numeric(%(max_digits)s, %(decimal_places)s)', 
    13     'FileField':         'varchar(%(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 sql_table_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

    old new  
    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 * 
     10from django.db.backends.sqlite3.client import DatabaseClient 
     11from django.db.backends.sqlite3.creation import DatabaseCreation 
     12from django.db.backends.sqlite3.introspection import DatabaseIntrospection 
     13 
    1014try: 
    1115    try: 
    1216        from sqlite3 import dbapi2 as Database 
     
    4650    Database.register_adapter(str, lambda s:s.decode('utf-8')) 
    4751 
    4852class DatabaseFeatures(BaseDatabaseFeatures): 
    49     supports_constraints = False 
    5053    # SQLite cannot handle us only partially reading from a cursor's result set 
    5154    # and then writing the same rows to the database in another cursor. This 
    5255    # setting ensures we always read result sets fully into memory all in one 
     
    9699        second = '%s-12-31 23:59:59.999999' 
    97100        return [first % value, second % value] 
    98101 
    99  
    100102class DatabaseWrapper(BaseDatabaseWrapper): 
    101     features = DatabaseFeatures() 
    102     ops = DatabaseOperations() 
    103  
     103     
    104104    # SQLite requires LIKE statements to include an ESCAPE clause if the value 
    105105    # being escaped has a percent or underscore in it. 
    106106    # See http://www.sqlite.org/lang_expr.html for an explanation. 
     
    121121        'iendswith': "LIKE %s ESCAPE '\\'", 
    122122    } 
    123123 
     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 = BaseDatabaseValidation() 
     133 
    124134    def _cursor(self, settings): 
    125135        if self.connection is None: 
    126136            if not settings.DATABASE_NAME: 
  • django/db/backends/sqlite3/client.py

    old new  
     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

    old new  
    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

    old new  
    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                     
  • django/db/backends/mysql/base.py

    old new  
    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 * 
     8from django.db.backends.mysql.client import DatabaseClient 
     9from django.db.backends.mysql.creation import DatabaseCreation 
     10from django.db.backends.mysql.introspection import DatabaseIntrospection 
     11from django.db.backends.mysql.validation import DatabaseValidation 
     12 
    813try: 
    914    import MySQLdb as Database 
    1015except ImportError, e: 
     
    6065# TRADITIONAL will automatically cause most warnings to be treated as errors. 
    6166 
    6267class DatabaseFeatures(BaseDatabaseFeatures): 
    63     inline_fk_references = False 
    6468  &nb