Ticket #5461: 5461-r8194.diff
| File 5461-r8194.diff, 142.7 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.dispatch import dispatcher 7 6 from django.test import signals 8 7 from django.template import Template 9 8 from django.utils.translation import deactivate 10 9 11 # The prefix to put on the default database name when creating12 # the test database.13 TEST_DATABASE_PREFIX = 'test_'14 15 10 def instrumented_test_render(self, context): 16 11 """ 17 12 An instrumented Template render method, providing a signal … … 71 66 72 67 del mail.outbox 73 68 74 def _set_autocommit(connection):75 "Make sure a connection is in autocommit mode."76 if hasattr(connection.connection, "autocommit"):77 if callable(connection.connection.autocommit):78 connection.connection.autocommit(True)79 else:80 connection.connection.autocommit = True81 elif hasattr(connection.connection, "set_isolation_level"):82 connection.connection.set_isolation_level(0)83 84 def get_mysql_create_suffix():85 suffix = []86 if settings.TEST_DATABASE_CHARSET:87 suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET)88 if settings.TEST_DATABASE_COLLATION:89 suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION)90 return ' '.join(suffix)91 92 def get_postgresql_create_suffix():93 assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time."94 if settings.TEST_DATABASE_CHARSET:95 return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET96 return ''97 98 def create_test_db(verbosity=1, autoclobber=False):99 """100 Creates a test database, prompting the user for confirmation if the101 database already exists. Returns the name of the test database created.102 """103 # If the database backend wants to create the test DB itself, let it104 creation_module = get_creation_module()105 if hasattr(creation_module, "create_test_db"):106 creation_module.create_test_db(settings, connection, verbosity, autoclobber)107 return108 109 if verbosity >= 1:110 print "Creating test database..."111 # If we're using SQLite, it's more convenient to test against an112 # in-memory database. Using the TEST_DATABASE_NAME setting you can still choose113 # to run on a physical database.114 if settings.DATABASE_ENGINE == "sqlite3":115 if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:":116 TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME117 # Erase the old test database118 if verbosity >= 1:119 print "Destroying old test database..."120 if os.access(TEST_DATABASE_NAME, os.F_OK):121 if not autoclobber:122 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)123 if autoclobber or confirm == 'yes':124 try:125 if verbosity >= 1:126 print "Destroying old test database..."127 os.remove(TEST_DATABASE_NAME)128 except Exception, e:129 sys.stderr.write("Got an error deleting the old test database: %s\n" % e)130 sys.exit(2)131 else:132 print "Tests cancelled."133 sys.exit(1)134 if verbosity >= 1:135 print "Creating test database..."136 else:137 TEST_DATABASE_NAME = ":memory:"138 else:139 suffix = {140 'postgresql': get_postgresql_create_suffix,141 'postgresql_psycopg2': get_postgresql_create_suffix,142 'mysql': get_mysql_create_suffix,143 }.get(settings.DATABASE_ENGINE, lambda: '')()144 if settings.TEST_DATABASE_NAME:145 TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME146 else:147 TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME148 149 qn = connection.ops.quote_name150 151 # Create the test database and connect to it. We need to autocommit152 # if the database supports it because PostgreSQL doesn't allow153 # CREATE/DROP DATABASE statements within transactions.154 cursor = connection.cursor()155 _set_autocommit(connection)156 try:157 cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))158 except Exception, e:159 sys.stderr.write("Got an error creating the test database: %s\n" % e)160 if not autoclobber:161 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)162 if autoclobber or confirm == 'yes':163 try:164 if verbosity >= 1:165 print "Destroying old test database..."166 cursor.execute("DROP DATABASE %s" % qn(TEST_DATABASE_NAME))167 if verbosity >= 1:168 print "Creating test database..."169 cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))170 except Exception, e:171 sys.stderr.write("Got an error recreating the test database: %s\n" % e)172 sys.exit(2)173 else:174 print "Tests cancelled."175 sys.exit(1)176 177 connection.close()178 settings.DATABASE_NAME = TEST_DATABASE_NAME179 180 call_command('syncdb', verbosity=verbosity, interactive=False)181 182 if settings.CACHE_BACKEND.startswith('db://'):183 cache_name = settings.CACHE_BACKEND[len('db://'):]184 call_command('createcachetable', cache_name)185 186 # Get a cursor (even though we don't need one yet). This has187 # the side effect of initializing the test database.188 cursor = connection.cursor()189 190 return TEST_DATABASE_NAME191 192 def destroy_test_db(old_database_name, verbosity=1):193 # If the database wants to drop the test DB itself, let it194 creation_module = get_creation_module()195 if hasattr(creation_module, "destroy_test_db"):196 creation_module.destroy_test_db(settings, connection, old_database_name, verbosity)197 return198 199 if verbosity >= 1:200 print "Destroying test database..."201 connection.close()202 TEST_DATABASE_NAME = settings.DATABASE_NAME203 settings.DATABASE_NAME = old_database_name204 if settings.DATABASE_ENGINE == "sqlite3":205 if TEST_DATABASE_NAME and TEST_DATABASE_NAME != ":memory:":206 # Remove the SQLite database file207 os.remove(TEST_DATABASE_NAME)208 else:209 # Remove the test database to clean up after210 # ourselves. Connect to the previous database (not the test database)211 # to do so, because it's not allowed to delete a database while being212 # connected to it.213 cursor = connection.cursor()214 _set_autocommit(connection)215 time.sleep(1) # To avoid "database is being accessed by other users" errors.216 cursor.execute("DROP DATABASE %s" % connection.ops.quote_name(TEST_DATABASE_NAME))217 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 15 15 # backends that ships with Django, so look there first. 16 16 _import_path = 'django.db.backends.' 17 17 backend = __import__('%s%s.base' % (_import_path, settings.DATABASE_ENGINE), {}, {}, ['']) 18 creation = __import__('%s%s.creation' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])19 18 except ImportError, e: 19 import traceback 20 traceback.print_exc() 20 21 # If the import failed, we might be looking for a database backend 21 22 # distributed external to Django. So we'll try that next. 22 23 try: 23 24 _import_path = '' 24 25 backend = __import__('%s.base' % settings.DATABASE_ENGINE, {}, {}, ['']) 25 creation = __import__('%s.creation' % settings.DATABASE_ENGINE, {}, {}, [''])26 26 except ImportError, e_user: 27 27 # The database backend wasn't found. Display a helpful error message 28 28 # listing all possible (built-in) database backends. … … 35 35 else: 36 36 raise # If there's some other error, this must be an error in Django itself. 37 37 38 def _import_database_module(import_path='', module_name=''):39 """Lazily import a database module when requested."""40 return __import__('%s%s.%s' % (import_path, settings.DATABASE_ENGINE, module_name), {}, {}, [''])41 42 # We don't want to import the introspect module unless someone asks for it, so43 # lazily load it on demmand.44 get_introspection_module = curry(_import_database_module, _import_path, 'introspection')45 46 def get_creation_module():47 return creation48 49 # We want runshell() to work the same way, but we have to treat it a50 # little differently (since it just runs instead of returning a module like51 # the above) and wrap the lazily-loaded runshell() method.52 runshell = lambda: _import_database_module(_import_path, "client").runshell()53 54 38 # Convenient aliases for backend bits. 55 39 connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS) 56 40 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 BaseDatabaseFeatures 8 from django.db.backends import BaseDatabaseValidation 9 from django.db.backends import BaseDatabaseWrapper 10 from django.db.backends import util 11 from django.db.backends.postgresql.client import DatabaseClient 12 from django.db.backends.postgresql.creation import DatabaseCreation 13 from django.db.backends.postgresql.introspection import DatabaseIntrospection 14 from django.db.backends.postgresql.operations import DatabaseOperations 7 15 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 16 10 17 try: 11 18 import psycopg as Database 12 19 except ImportError, e: … … 62 69 class DatabaseFeatures(BaseDatabaseFeatures): 63 70 pass # This backend uses all the defaults. 64 71 72 class DatabaseValidation(BaseDatabaseValidation): 73 pass 74 65 75 class DatabaseWrapper(BaseDatabaseWrapper): 66 76 features = DatabaseFeatures() 67 77 ops = DatabaseOperations() 78 client = DatabaseClient() 79 creation = DatabaseCreation(ops, features) 80 introspection = DatabaseIntrospection(ops) 81 validation = DatabaseValidation() 82 68 83 operators = { 69 84 'exact': '= %s', 70 85 'iexact': 'ILIKE %s', -
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 __init__(self, ops): 22 self.ops = ops 23 24 def get_table_list(self, cursor): 25 "Returns a list of table names in the current database." 26 cursor.execute(""" 27 SELECT c.relname 28 FROM pg_catalog.pg_class c 29 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 30 WHERE c.relkind IN ('r', 'v', '') 31 AND n.nspname NOT IN ('pg_catalog', 'pg_toast') 32 AND pg_catalog.pg_table_is_visible(c.oid)""") 33 return [row[0] for row in cursor.fetchall()] 4 34 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()] 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.ops.quote_name(table_name)) 38 return cursor.description 15 39 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 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 con.conkey, con.confkey, c2.relname 47 FROM pg_constraint con, pg_class c1, pg_class c2 48 WHERE c1.oid = con.conrelid 49 AND c2.oid = con.confrelid 50 AND c1.relname = %s 51 AND con.contype = 'f'""", [table_name]) 52 relations = {} 53 for row in cursor.fetchall(): 54 try: 55 # row[0] and row[1] are like "{2}", so strip the curly braces. 56 relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2]) 57 except ValueError: 58 continue 59 return relations 20 60 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 61 def get_indexes(self, cursor, table_name): 62 """ 63 Returns a dictionary of fieldname -> infodict for the given table, 64 where each infodict is in the format: 65 {'primary_key': boolean representing whether it's the primary key, 66 'unique': boolean representing whether it's a unique index} 67 """ 68 # This query retrieves each index on the given table, including the 69 # first associated field name 70 cursor.execute(""" 71 SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary 72 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, 73 pg_catalog.pg_index idx, pg_catalog.pg_attribute attr 74 WHERE c.oid = idx.indrelid 75 AND idx.indexrelid = c2.oid 76 AND attr.attrelid = c.oid 77 AND attr.attnum = idx.indkey[0] 78 AND c.relname = %s""", [table_name]) 79 indexes = {} 80 for row in cursor.fetchall(): 81 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 82 # a string of space-separated integers. This designates the field 83 # indexes (1-based) of the fields that have indexes on the table. 84 # Here, we skip any indexes across multiple fields. 85 if ' ' in row[1]: 86 continue 87 indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]} 88 return indexes 41 89 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 _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 BaseDatabaseWrapper 10 from django.db.backends import BaseDatabaseFeatures 11 from django.db.backends import BaseDatabaseOperations 12 from django.db.backends import BaseDatabaseValidation 13 from django.db.backends import util 14 from django.db.backends.sqlite3.client import DatabaseClient 15 from django.db.backends.sqlite3.creation import DatabaseCreation 16 from django.db.backends.sqlite3.introspection import DatabaseIntrospection 17 10 18 try: 11 19 try: 12 20 from sqlite3 import dbapi2 as Database … … 89 97 second = '%s-12-31 23:59:59.999999' 90 98 return [first % value, second % value] 91 99 100 class DatabaseValidation(BaseDatabaseValidation): 101 pass 92 102 93 103 class DatabaseWrapper(BaseDatabaseWrapper): 94 104 features = DatabaseFeatures() 95 105 ops = DatabaseOperations() 96 106 client = DatabaseClient() 107 creation = DatabaseCreation(ops, features) 108 introspection = DatabaseIntrospection(ops) 109 validation = DatabaseValidation() 110 97 111 # SQLite requires LIKE statements to include an ESCAPE clause if the value 98 112 # being escaped has a percent or underscore in it. 99 113 # See http://www.sqlite.org/lang_expr.html for an explanation. -
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 __init__(self, ops): 39 self.ops = ops 40 41 def get_table_list(self, cursor): 42 "Returns a list of table names in the current database." 43 # Skip the sqlite_sequence system table used for autoincrement key 44 # generation. 45 cursor.execute(""" 46 SELECT name FROM sqlite_master 47 WHERE type='table' AND NOT name='sqlite_sequence' 48 ORDER BY name""") 49 return [row[0] for row in cursor.fetchall()] 50 51 def get_table_description(self, cursor, table_name): 52 "Returns a description of the table, with the DB-API cursor.description interface." 53 return [(info['name'], info['type'], None, None, None, None, 54 info['null_ok']) for info in self._table_info(cursor, table_name)] 55 56 def get_relations(self, cursor, table_name): 57 raise NotImplementedError 58 59 def get_indexes(self, cursor, table_name): 60 """ 61 Returns a dictionary of fieldname -> infodict for the given table, 62 where each infodict is in the format: 63 {'primary_key': boolean representing whether it's the primary key, 64 'unique': boolean representing whether it's a unique index} 65 """ 66 indexes = {} 67 for info in self._table_info(cursor, table_name): 68 indexes[info['name']] = {'primary_key': info['pk'] != 0, 69 'unique': False} 70 cursor.execute('PRAGMA index_list(%s)' % self.ops.quote_name(table_name)) 71 # seq, name, unique 72 for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]: 73 if not unique: 74 continue 75 cursor.execute('PRAGMA index_info(%s)' % self.ops.quote_name(index)) 76 info = cursor.fetchall() 77 # Skip indexes across multiple fields 78 if len(info) != 1: 79 continue 80 name = info[0][2] # seqno, cid, name 81 indexes[name]['unique'] = True 82 return indexes 83 84 def _table_info(self, cursor, name): 85 cursor.execute('PRAGMA table_info(%s)' % self.ops.quote_name(name)) 86 # cid, name, type, notnull, dflt_value, pk 87 return [{'name': field[1], 88 'type': field[2], 89 'null_ok': not field[3], 90 'pk': field[5] # undocumented 91 } for field in cursor.fetchall()] 92 -
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 _create_test_db(self, connection, verbosity, autoclobber): 36 if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:": 37 test_database_name = settings.TEST_DATABASE_NAME 38 # Erase the old test database 39 if verbosity >= 1: 40 print "Destroying old test database..." 41 if os.access(test_database_name, os.F_OK): 42 if not autoclobber: 43 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % test_database_name) 44 if autoclobber or confirm == 'yes': 45 try: 46 if verbosity >= 1: 47 print "Destroying old test database..." 48 os.remove(test_database_name) 49 except Exception, e: 50 sys.stderr.write("Got an error deleting the old test database: %s\n" % e) 51 sys.exit(2) 52 else: 53 print "Tests cancelled." 54 sys.exit(1) 55 if verbosity >= 1: 56 print "Creating test database..." 57 else: 58 test_database_name = ":memory:" 59 return test_database_name 60 61 def _destroy_test_db(self, connection, test_database_name, verbosity): 62 if test_database_name and test_database_name != ":memory:": 63 # Remove the SQLite database file 64 os.remove(test_database_name) 65 -
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 BaseDatabaseFeatures 8 from django.db.backends import BaseDatabaseOperations 9 from django.db.backends import BaseDatabaseWrapper 10 from django.db.backends import util 11 from django.db.backends.mysql.client import DatabaseClient 12 from django.db.backends.mysql.creation import DatabaseCreation 13 from django.db.backends.mysql.introspection import DatabaseIntrospection 14 from django.db.backends.mysql.validation import DatabaseValidation 15 8 16 try: 9 17 import MySQLdb as Database 10 18 except ImportError, e: … … 144 152 class DatabaseWrapper(BaseDatabaseWrapper): 145 153 features = DatabaseFeatures() 146 154 ops = DatabaseOperations() 155 client = DatabaseClient() 156 creation = DatabaseCreation(ops, features) 157 introspection = DatabaseIntrospection(ops) 158 validation = DatabaseValidation() 159 147 160 operators = { 148 161 'exact': '= BINARY %s', 149 162 'iexact': 'LIKE %s', -
django/db/backends/mysql/validation.py
old new 1 from django.db.backends import BaseDatabaseValidation 2 3 class 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 -
django/db/backends/mysql/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 = [''] 6 db = settings.DATABASE_OPTIONS.get('db', settings.DATABASE_NAME) 7 user = settings.DATABASE_OPTIONS.get('user', settings.DATABASE_USER) 8 passwd = settings.DATABASE_OPT
