Ticket #5461: 5461-r8280.diff
| File 5461-r8280.diff, 167.4 kB (added by russellm, 5 months ago) |
|---|
-
django/test/simple.py
old new 3 3 from django.db.models import get_app, get_apps 4 4 from django.test import _doctest as doctest 5 5 from django.test.utils import setup_test_environment, teardown_test_environment 6 from django.test.utils import create_test_db, destroy_test_db7 6 from django.test.testcases import OutputChecker, DocTestRunner 8 7 9 8 # The module name for tests outside models.py … … 139 138 suite.addTest(test) 140 139 141 140 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) 143 143 result = unittest.TextTestRunner(verbosity=verbosity).run(suite) 144 destroy_test_db(old_name, verbosity)144 connection.creation.destroy_test_db(old_name, verbosity) 145 145 146 146 teardown_test_environment() 147 147 -
django/test/utils.py
old new 1 1 import sys, time, os 2 2 from django.conf import settings 3 from django.db import connection , get_creation_module3 from django.db import connection 4 4 from django.core import mail 5 from django.core.management import call_command6 5 from django.test import signals 7 6 from django.template import Template 8 7 from django.utils.translation import deactivate 9 8 10 # The prefix to put on the default database name when creating11 # the test database.12 TEST_DATABASE_PREFIX = 'test_'13 14 9 def instrumented_test_render(self, context): 15 10 """ 16 11 An instrumented Template render method, providing a signal … … 70 65 71 66 del mail.outbox 72 67 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 = True80 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_CHARSET95 return ''96 97 def create_test_db(verbosity=1, autoclobber=False):98 """99 Creates a test database, prompting the user for confirmation if the100 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 it103 creation_module = get_creation_module()104 if hasattr(creation_module, "create_test_db"):105 creation_module.create_test_db(settings, connection, verbosity, autoclobber)106 return107 108 if verbosity >= 1:109 print "Creating test database..."110 # If we're using SQLite, it's more convenient to test against an111 # in-memory database. Using the TEST_DATABASE_NAME setting you can still choose112 # 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_NAME116 # Erase the old test database117 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_NAME145 else:146 TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME147 148 qn = connection.ops.quote_name149 150 # Create the test database and connect to it. We need to autocommit151 # if the database supports it because PostgreSQL doesn't allow152 # 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_NAME178 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 has186 # the side effect of initializing the test database.187 cursor = connection.cursor()188 189 return TEST_DATABASE_NAME190 191 def destroy_test_db(old_database_name, verbosity=1):192 # If the database wants to drop the test DB itself, let it193 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 return197 198 if verbosity >= 1:199 print "Destroying test database..."200 connection.close()201 TEST_DATABASE_NAME = settings.DATABASE_NAME202 settings.DATABASE_NAME = old_database_name203 if settings.DATABASE_ENGINE == "sqlite3":204 if TEST_DATABASE_NAME and TEST_DATABASE_NAME != ":memory:":205 # Remove the SQLite database file206 os.remove(TEST_DATABASE_NAME)207 else:208 # Remove the test database to clean up after209 # ourselves. Connect to the previous database (not the test database)210 # to do so, because it's not allowed to delete a database while being211 # 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 7 7 except ImportError: 8 8 from django.utils import _decimal as decimal # for Python 2.3 9 9 10 from django.db import connection , get_creation_module10 from django.db import connection 11 11 from django.db.models import signals 12 12 from django.db.models.query_utils import QueryWrapper 13 13 from django.dispatch import dispatcher … … 145 145 # as the TextField Django field type, which means XMLField's 146 146 # get_internal_type() returns 'TextField'. 147 147 # 148 # But the limitation of the get_internal_type() / DATA_TYPESapproach148 # But the limitation of the get_internal_type() / data_types approach 149 149 # is that it cannot handle database column types that aren't already 150 150 # mapped to one of the built-in Django field types. In this case, you 151 151 # can implement db_type() instead of get_internal_type() to specify 152 152 # exactly which wacky database column type you want to use. 153 153 data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_") 154 154 try: 155 return get_creation_module().DATA_TYPES[self.get_internal_type()] % data155 return connection.creation.data_types[self.get_internal_type()] % data 156 156 except KeyError: 157 157 return None 158 158 -
django/db/__init__.py
old new 14 14 # backends that ships with Django, so look there first. 15 15 _import_path = 'django.db.backends.' 16 16 backend = __import__('%s%s.base' % (_import_path, settings.DATABASE_ENGINE), {}, {}, ['']) 17 creation = __import__('%s%s.creation' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])18 17 except ImportError, e: 19 18 # If the import failed, we might be looking for a database backend 20 19 # distributed external to Django. So we'll try that next. 21 20 try: 22 21 _import_path = '' 23 22 backend = __import__('%s.base' % settings.DATABASE_ENGINE, {}, {}, ['']) 24 creation = __import__('%s.creation' % settings.DATABASE_ENGINE, {}, {}, [''])25 23 except ImportError, e_user: 26 24 # The database backend wasn't found. Display a helpful error message 27 25 # listing all possible (built-in) database backends. … … 29 27 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')] 30 28 available_backends.sort() 31 29 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))) 34 32 else: 35 33 raise # If there's some other error, this must be an error in Django itself. 36 34 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, so42 # lazily load it on demmand.43 get_introspection_module = curry(_import_database_module, _import_path, 'introspection')44 45 def get_creation_module():46 return creation47 48 # We want runshell() to work the same way, but we have to treat it a49 # little differently (since it just runs instead of returning a module like50 # the above) and wrap the lazily-loaded runshell() method.51 runshell = lambda: _import_database_module(_import_path, "client").runshell()52 53 35 # Convenient aliases for backend bits. 54 36 connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS) 55 37 DatabaseError = backend.DatabaseError -
django/db/backends/postgresql/base.py
old new 4 4 Requires psycopg 1: http://initd.org/projects/psycopg1 5 5 """ 6 6 7 from django.db.backends import * 8 from django.db.backends.postgresql.client import DatabaseClient 9 from django.db.backends.postgresql.creation import DatabaseCreation 10 from django.db.backends.postgresql.introspection import DatabaseIntrospection 11 from django.db.backends.postgresql.operations import DatabaseOperations 7 12 from 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 10 14 try: 11 15 import psycopg as Database 12 16 except ImportError, e: … … 59 63 def __iter__(self): 60 64 return iter(self.cursor) 61 65 62 class DatabaseFeatures(BaseDatabaseFeatures):63 pass # This backend uses all the defaults.64 65 66 class DatabaseWrapper(BaseDatabaseWrapper): 66 features = DatabaseFeatures()67 ops = DatabaseOperations()68 67 operators = { 69 68 'exact': '= %s', 70 69 'iexact': 'ILIKE %s', … … 82 81 'iendswith': 'ILIKE %s', 83 82 } 84 83 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 85 94 def _cursor(self, settings): 86 95 set_tz = False 87 96 if self.connection is None: -
django/db/backends/postgresql/client.py
old new 1 from django.db.backends import BaseDatabaseClient 1 2 from django.conf import settings 2 3 import os 3 4 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) 5 class 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 DatabaseOperations1 from django.db.backends import BaseDatabaseIntrospection 2 2 3 quote_name = DatabaseOperations().quote_name 3 class 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()] 4 31 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 15 36 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 20 57 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 41 86 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 the50 # first associated field name51 cursor.execute("""52 SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary53 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,54 pg_catalog.pg_index idx, pg_catalog.pg_attribute attr55 WHERE c.oid = idx.indrelid56 AND idx.indexrelid = c2.oid57 AND attr.attrelid = c.oid58 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 as63 # a string of space-separated integers. This designates the field64 # 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 continue68 indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}69 return indexes70 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 } 1 from django.conf import settings 2 from django.db.backends.creation import BaseDatabaseCreation 3 4 class 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 6 6 Python 2.5 and later use the sqlite3 module in the standard library. 7 7 """ 8 8 9 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 9 from django.db.backends import * 10 from django.db.backends.sqlite3.client import DatabaseClient 11 from django.db.backends.sqlite3.creation import DatabaseCreation 12 from django.db.backends.sqlite3.introspection import DatabaseIntrospection 13 10 14 try: 11 15 try: 12 16 from sqlite3 import dbapi2 as Database … … 46 50 Database.register_adapter(str, lambda s:s.decode('utf-8')) 47 51 48 52 class DatabaseFeatures(BaseDatabaseFeatures): 49 supports_constraints = False50 53 # SQLite cannot handle us only partially reading from a cursor's result set 51 54 # and then writing the same rows to the database in another cursor. This 52 55 # setting ensures we always read result sets fully into memory all in one … … 96 99 second = '%s-12-31 23:59:59.999999' 97 100 return [first % value, second % value] 98 101 99 100 102 class DatabaseWrapper(BaseDatabaseWrapper): 101 features = DatabaseFeatures() 102 ops = DatabaseOperations() 103 103 104 104 # SQLite requires LIKE statements to include an ESCAPE clause if the value 105 105 # being escaped has a percent or underscore in it. 106 106 # See http://www.sqlite.org/lang_expr.html for an explanation. … … 121 121 'iendswith': "LIKE %s ESCAPE '\\'", 122 122 } 123 123 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 124 134 def _cursor(self, settings): 125 135 if self.connection is None: 126 136 if not settings.DATABASE_NAME: -
django/db/backends/sqlite3/client.py
old new 1 from django.db.backends import BaseDatabaseClient 1 2 from django.conf import settings 2 3 import os 3 4 4 def runshell(): 5 args = ['', settings.DATABASE_NAME] 6 os.execvp('sqlite3', args) 5 class 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 DatabaseOperations1 from django.db.backends import BaseDatabaseIntrospection 2 2 3 quote_name = DatabaseOperations().quote_name4 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 key8 # generation.9 cursor.execute("""10 SELECT name FROM sqlite_master11 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 NotImplementedError22 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, unique36 for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]:37 if not unique:38 continue39 cursor.execute('PRAGMA index_info(%s)' % quote_name(index))40 info = cursor.fetchall()41 # Skip indexes across multiple fields42 if len(info) != 1:43 continue44 name = info[0][2] # seqno, cid, name45 indexes[name]['unique'] = True46 return indexes47 48 def _table_info(cursor, name):49 cursor.execute('PRAGMA table_info(%s)' % quote_name(name))50 # cid, name, type, notnull, dflt_value, pk51 return [{'name': field[1],52 'type': field[2],53 'null_ok': not field[3],54 'pk': field[5] # undocumented55 } for field in cursor.fetchall()]56 57 # Maps SQL types to Django Field types. Some of the SQL types have multiple58 # entries here because SQLite allows for anything and doesn't normalize the59 # 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 74 3 # This light wrapper "fakes" a dictionary interface, because some SQLite data 75 4 # types include variables in them -- e.g. "varchar(30)" -- and can't be matched 76 5 # as a simple dictionary lookup. 77 6 class 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 78 24 def __getitem__(self, key): 79 25 key = key.lower() 80 26 try: 81 return BASE_DATA_TYPES_REVERSE[key]27 return self.base_data_types_reverse[key] 82 28 except KeyError: 83 29 import re 84 30 m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key) … … 86 32 return ('CharField', {'max_length': int(m.group(1))}) 87 33 raise KeyError 88 34 89 DATA_TYPES_REVERSE = FlexibleFieldLookupDict() 35 class 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 } 1 import os 2 import sys 3 from django.conf import settings 4 from django.db.backends.creation import BaseDatabaseCreation 5 6 class 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 4 4 Requires MySQLdb: http://sourceforge.net/projects/mysql-python 5 5 """ 6 6 7 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 7 from django.db.backends import * 8 from django.db.backends.mysql.client import DatabaseClient 9 from django.db.backends.mysql.creation import DatabaseCreation 10 from django.db.backends.mysql.introspection import DatabaseIntrospection 11 from django.db.backends.mysql.validation import DatabaseValidation 12 8 13 try: 9 14 import MySQLdb as Database 10 15 except ImportError, e: … … 60 65 # TRADITIONAL will automatically cause most warnings to be treated as errors. 61 66 62 67 class DatabaseFeatures(BaseDatabaseFeatures): 63 inline_fk_references = False64 68 &nb
