From aecff3e2459e0038b7c66fed975b28a6d2829a65 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Wed, 14 Dec 2005 06:24:32 +0000 Subject: [PATCH] magic-removal: Various cleanup and moving, with respect to the recent django.core.db -> django.db move git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@1637 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/cache.py | 16 +- django/core/management.py | 191 +++++++++---------- django/db/__init__.py | 8 +- django/db/backends/ado_mssql/base.py | 35 +--- django/db/backends/ado_mssql/creation.py | 26 +++ django/db/backends/mysql/base.py | 39 +--- django/db/backends/mysql/creation.py | 30 +++ django/db/backends/postgresql/base.py | 39 +--- django/db/backends/postgresql/creation.py | 30 +++ django/db/backends/sqlite3/base.py | 38 +--- django/db/backends/sqlite3/creation.py | 29 +++ django/db/models/__init__.py | 220 ++++++++++------------ tests/modeltests/custom_methods/models.py | 4 +- tests/othertests/db_typecasts.py | 4 +- tests/runtests.py | 18 +- 15 files changed, 356 insertions(+), 371 deletions(-) create mode 100644 django/db/backends/ado_mssql/creation.py create mode 100644 django/db/backends/mysql/creation.py create mode 100644 django/db/backends/postgresql/creation.py create mode 100644 django/db/backends/sqlite3/creation.py diff --git a/django/core/cache.py b/django/core/cache.py index a619dd3fbf..7216f8f8de 100644 --- a/django/core/cache.py +++ b/django/core/cache.py @@ -360,7 +360,7 @@ class _FileCache(_SimpleCache): ############# import base64 -from django.core.db import db, DatabaseError +from django.db import connection, DatabaseError from datetime import datetime class _DBCache(_Cache): @@ -380,7 +380,7 @@ class _DBCache(_Cache): self._cull_frequency = 3 def get(self, key, default=None): - cursor = db.cursor() + cursor = connection.cursor() cursor.execute("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % self._table, [key]) row = cursor.fetchone() if row is None: @@ -388,14 +388,14 @@ class _DBCache(_Cache): now = datetime.now() if row[2] < now: cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % self._table, [key]) - db.commit() + connection.commit() return default return pickle.loads(base64.decodestring(row[1])) def set(self, key, value, timeout=None): if timeout is None: timeout = self.default_timeout - cursor = db.cursor() + cursor = connection.cursor() cursor.execute("SELECT COUNT(*) FROM %s" % self._table) num = cursor.fetchone()[0] now = datetime.now().replace(microsecond=0) @@ -413,15 +413,15 @@ class _DBCache(_Cache): # To be threadsafe, updates/inserts are allowed to fail silently pass else: - db.commit() + connection.commit() def delete(self, key): - cursor = db.cursor() + cursor = connection.cursor() cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % self._table, [key]) - db.commit() + connection.commit() def has_key(self, key): - cursor = db.cursor() + cursor = connection.cursor() cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % self._table, [key]) return cursor.fetchone() is not None diff --git a/django/core/management.py b/django/core/management.py index 81de2cadcf..82e3d360f0 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -22,9 +22,9 @@ PROJECT_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', '%s_template') INVALID_PROJECT_NAMES = ('django', 'test') def _get_packages_insert(app_label): - from django.core.db import db + from django.db import backend return "INSERT INTO %s (%s, %s) VALUES ('%s', '%s');" % \ - (db.quote_name('packages'), db.quote_name('label'), db.quote_name('name'), + (backend.quote_name('packages'), backend.quote_name('label'), backend.quote_name('name'), app_label, app_label) def _get_permission_codename(action, opts): @@ -39,16 +39,16 @@ def _get_all_permissions(opts): return perms + list(opts.permissions) def _get_permission_insert(name, codename, opts): - from django.core.db import db + from django.db import backend return "INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s');" % \ - (db.quote_name('auth_permissions'), db.quote_name('name'), db.quote_name('package'), - db.quote_name('codename'), name.replace("'", "''"), opts.app_label, codename) + (backend.quote_name('auth_permissions'), backend.quote_name('name'), backend.quote_name('package'), + backend.quote_name('codename'), name.replace("'", "''"), opts.app_label, codename) def _get_contenttype_insert(opts): - from django.core.db import db + from django.db import backend return "INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s');" % \ - (db.quote_name('content_types'), db.quote_name('name'), db.quote_name('package'), - db.quote_name('python_module_name'), opts.verbose_name, opts.app_label, opts.module_name) + (backend.quote_name('content_types'), backend.quote_name('name'), backend.quote_name('package'), + backend.quote_name('python_module_name'), opts.verbose_name, opts.app_label, opts.module_name) def _is_valid_dir_name(s): return bool(re.search(r'^\w+$', s)) @@ -60,8 +60,8 @@ get_rel_data_type = lambda f: (f.get_internal_type() == 'AutoField') and 'Intege def get_sql_create(mod): "Returns a list of the CREATE TABLE SQL statements for the given module." - from django.core import db - from django.db import models + from django.db import backend, get_creation_module, models + data_types = get_creation_module().DATA_TYPES final_output = [] for klass in mod._MODELS: opts = klass._meta @@ -73,9 +73,9 @@ def get_sql_create(mod): else: rel_field = f data_type = f.get_internal_type() - col_type = db.DATA_TYPES[data_type] + col_type = data_types[data_type] if col_type is not None: - field_output = [db.db.quote_name(f.column), col_type % rel_field.__dict__] + field_output = [backend.quote_name(f.column), col_type % rel_field.__dict__] field_output.append('%sNULL' % (not f.null and 'NOT ' or '')) if f.unique: field_output.append('UNIQUE') @@ -83,16 +83,16 @@ def get_sql_create(mod): field_output.append('PRIMARY KEY') if f.rel: field_output.append('REFERENCES %s (%s)' % \ - (db.db.quote_name(f.rel.to._meta.db_table), - db.db.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column))) + (backend.quote_name(f.rel.to._meta.db_table), + backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column))) table_output.append(' '.join(field_output)) if opts.order_with_respect_to: - table_output.append('%s %s NULL' % (db.db.quote_name('_order'), db.DATA_TYPES['IntegerField'])) + table_output.append('%s %s NULL' % (backend.quote_name('_order'), data_types['IntegerField'])) for field_constraints in opts.unique_together: table_output.append('UNIQUE (%s)' % \ - ", ".join([db.db.quote_name(opts.get_field(f).column) for f in field_constraints])) + ", ".join([backend.quote_name(opts.get_field(f).column) for f in field_constraints])) - full_statement = ['CREATE TABLE %s (' % db.db.quote_name(opts.db_table)] + full_statement = ['CREATE TABLE %s (' % backend.quote_name(opts.db_table)] for i, line in enumerate(table_output): # Combine and add commas. full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) full_statement.append(');') @@ -101,21 +101,21 @@ def get_sql_create(mod): for klass in mod._MODELS: opts = klass._meta for f in opts.many_to_many: - table_output = ['CREATE TABLE %s (' % db.db.quote_name(f.get_m2m_db_table(opts))] - table_output.append(' %s %s NOT NULL PRIMARY KEY,' % (db.db.quote_name('id'), db.DATA_TYPES['AutoField'])) + table_output = ['CREATE TABLE %s (' % backend.quote_name(f.get_m2m_db_table(opts))] + table_output.append(' %s %s NOT NULL PRIMARY KEY,' % (backend.quote_name('id'), data_types['AutoField'])) table_output.append(' %s %s NOT NULL REFERENCES %s (%s),' % \ - (db.db.quote_name(opts.object_name.lower() + '_id'), - db.DATA_TYPES[get_rel_data_type(opts.pk)] % opts.pk.__dict__, - db.db.quote_name(opts.db_table), - db.db.quote_name(opts.pk.column))) + (backend.quote_name(opts.object_name.lower() + '_id'), + data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__, + backend.quote_name(opts.db_table), + backend.quote_name(opts.pk.column))) table_output.append(' %s %s NOT NULL REFERENCES %s (%s),' % \ - (db.db.quote_name(f.rel.to._meta.object_name.lower() + '_id'), - db.DATA_TYPES[get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__, - db.db.quote_name(f.rel.to._meta.db_table), - db.db.quote_name(f.rel.to._meta.pk.column))) + (backend.quote_name(f.rel.to._meta.object_name.lower() + '_id'), + data_types[get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__, + backend.quote_name(f.rel.to._meta.db_table), + backend.quote_name(f.rel.to._meta.pk.column))) table_output.append(' UNIQUE (%s, %s)' % \ - (db.db.quote_name(opts.object_name.lower() + '_id'), - db.db.quote_name(f.rel.to._meta.object_name.lower() + '_id'))) + (backend.quote_name(opts.object_name.lower() + '_id'), + backend.quote_name(f.rel.to._meta.object_name.lower() + '_id'))) table_output.append(');') final_output.append('\n'.join(table_output)) return final_output @@ -124,9 +124,10 @@ get_sql_create.args = APP_ARGS def get_sql_delete(mod): "Returns a list of the DROP TABLE SQL statements for the given module." - from django.core import db + from django.db import backend, connection + try: - cursor = db.db.cursor() + cursor = connection.cursor() except: cursor = None @@ -135,10 +136,10 @@ def get_sql_delete(mod): try: if cursor is not None: # Check whether the table exists. - cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name('django_admin_log')) + cursor.execute("SELECT 1 FROM %s LIMIT 1" % backend.quote_name('django_admin_log')) except: # The table doesn't exist, so it doesn't need to be dropped. - db.db.rollback() + connection.rollback() admin_log_exists = False else: admin_log_exists = True @@ -150,12 +151,12 @@ def get_sql_delete(mod): try: if cursor is not None: # Check whether the table exists. - cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name(klass._meta.db_table)) + cursor.execute("SELECT 1 FROM %s LIMIT 1" % backend.quote_name(klass._meta.db_table)) except: # The table doesn't exist, so it doesn't need to be dropped. - db.db.rollback() + connection.rollback() else: - output.append("DROP TABLE %s;" % db.db.quote_name(klass._meta.db_table)) + output.append("DROP TABLE %s;" % backend.quote_name(klass._meta.db_table)) # Output DROP TABLE statements for many-to-many tables. for klass in mod._MODELS: @@ -163,36 +164,36 @@ def get_sql_delete(mod): for f in opts.many_to_many: try: if cursor is not None: - cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name(f.get_m2m_db_table(opts))) + cursor.execute("SELECT 1 FROM %s LIMIT 1" % backend.quote_name(f.get_m2m_db_table(opts))) except: - db.db.rollback() + connection.rollback() else: - output.append("DROP TABLE %s;" % db.db.quote_name(f.get_m2m_db_table(opts))) + output.append("DROP TABLE %s;" % backend.quote_name(f.get_m2m_db_table(opts))) app_label = mod._MODELS[0]._meta.app_label # Delete from packages, auth_permissions, content_types. output.append("DELETE FROM %s WHERE %s = '%s';" % \ - (db.db.quote_name('packages'), db.db.quote_name('label'), app_label)) + (backend.quote_name('packages'), backend.quote_name('label'), app_label)) output.append("DELETE FROM %s WHERE %s = '%s';" % \ - (db.db.quote_name('auth_permissions'), db.db.quote_name('package'), app_label)) + (backend.quote_name('auth_permissions'), backend.quote_name('package'), app_label)) output.append("DELETE FROM %s WHERE %s = '%s';" % \ - (db.db.quote_name('content_types'), db.db.quote_name('package'), app_label)) + (backend.quote_name('content_types'), backend.quote_name('package'), app_label)) # Delete from the admin log. if cursor is not None: cursor.execute("SELECT %s FROM %s WHERE %s = %%s" % \ - (db.db.quote_name('id'), db.db.quote_name('content_types'), - db.db.quote_name('package')), [app_label]) + (backend.quote_name('id'), backend.quote_name('content_types'), + backend.quote_name('package')), [app_label]) if admin_log_exists: for row in cursor.fetchall(): output.append("DELETE FROM %s WHERE %s = %s;" % \ - (db.db.quote_name('django_admin_log'), db.db.quote_name('content_type_id'), row[0])) + (backend.quote_name('django_admin_log'), backend.quote_name('content_type_id'), row[0])) # Close database connection explicitly, in case this output is being piped # directly into a database client, to avoid locking issues. cursor.close() - db.db.close() + connection.close() return output[::-1] # Reverse it, to deal with table dependencies. get_sql_delete.help_doc = "Prints the DROP TABLE SQL statements for the given model module name(s)." @@ -206,7 +207,7 @@ get_sql_reset.args = APP_ARGS def get_sql_initial_data(mod): "Returns a list of the initial INSERT SQL statements for the given module." - from django.core import db + from django.conf.settings import DATABASE_ENGINE output = [] app_label = mod._MODELS[0]._meta.app_label output.append(_get_packages_insert(app_label)) @@ -215,7 +216,7 @@ def get_sql_initial_data(mod): opts = klass._meta # Add custom SQL, if it's available. - sql_files = [os.path.join(app_dir, opts.module_name + '.' + db.DATABASE_ENGINE + '.sql'), + sql_files = [os.path.join(app_dir, opts.module_name + '.' + DATABASE_ENGINE + '.sql'), os.path.join(app_dir, opts.module_name + '.sql')] for sql_file in sql_files: if os.path.exists(sql_file): @@ -234,25 +235,24 @@ get_sql_initial_data.args = APP_ARGS def get_sql_sequence_reset(mod): "Returns a list of the SQL statements to reset PostgreSQL sequences for the given module." - from django.core import db - from django.db import models + from django.db import backend, models output = [] for klass in mod._MODELS: for f in klass._meta.fields: if isinstance(f, models.AutoField): output.append("SELECT setval('%s_%s_seq', (SELECT max(%s) FROM %s));" % \ - (klass._meta.db_table, f.column, db.db.quote_name(f.column), - db.db.quote_name(klass._meta.db_table))) + (klass._meta.db_table, f.column, backend.quote_name(f.column), + backend.quote_name(klass._meta.db_table))) for f in klass._meta.many_to_many: output.append("SELECT setval('%s_id_seq', (SELECT max(%s) FROM %s));" % \ - (f.get_m2m_db_table(klass._meta), db.db.quote_name('id'), f.get_m2m_db_table(klass._meta))) + (f.get_m2m_db_table(klass._meta), backend.quote_name('id'), f.get_m2m_db_table(klass._meta))) return output get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting PostgreSQL sequences for the given model module name(s)." get_sql_sequence_reset.args = APP_ARGS def get_sql_indexes(mod): "Returns a list of the CREATE INDEX SQL statements for the given module." - from django.core.db import db + from django.db import backend output = [] for klass in mod._MODELS: for f in klass._meta.fields: @@ -260,7 +260,7 @@ def get_sql_indexes(mod): unique = f.unique and "UNIQUE " or "" output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \ (unique, klass._meta.db_table, f.column, - db.quote_name(klass._meta.db_table), db.quote_name(f.column))) + backend.quote_name(klass._meta.db_table), backend.quote_name(f.column))) return output get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)." get_sql_indexes.args = APP_ARGS @@ -282,13 +282,13 @@ def has_no_records(cursor): def database_check(mod): "Checks that everything is properly installed in the database for the given module." - from django.core import db - cursor = db.db.cursor() + from django.db import backend, connection + cursor = connection.cursor() app_label = mod._MODELS[0]._meta.app_label # Check that the package exists in the database. cursor.execute("SELECT 1 FROM %s WHERE %s = %%s" % \ - (db.db.quote_name('packages'), db.db.quote_name('label')), [app_label]) + (backend.quote_name('packages'), backend.quote_name('label')), [app_label]) if has_no_records(cursor): # sys.stderr.write("The '%s' package isn't installed.\n" % app_label) print _get_packages_insert(app_label) @@ -303,14 +303,14 @@ def database_check(mod): contenttypes_seen[opts.module_name] = 1 for codename, name in perms: cursor.execute("SELECT 1 FROM %s WHERE %s = %%s AND %s = %%s" % \ - (db.db.quote_name('auth_permissions'), db.db.quote_name('package'), - db.db.quote_name('codename')), (app_label, codename)) + (backend.quote_name('auth_permissions'), backend.quote_name('package'), + backend.quote_name('codename')), (app_label, codename)) if has_no_records(cursor): # sys.stderr.write("The '%s.%s' permission doesn't exist.\n" % (app_label, codename)) print _get_permission_insert(name, codename, opts) cursor.execute("SELECT 1 FROM %s WHERE %s = %%s AND %s = %%s" % \ - (db.db.quote_name('content_types'), db.db.quote_name('package'), - db.db.quote_name('python_module_name')), (app_label, opts.module_name)) + (backend.quote_name('content_types'), backend.quote_name('package'), + backend.quote_name('python_module_name')), (app_label, opts.module_name)) if has_no_records(cursor): # sys.stderr.write("The '%s.%s' content type doesn't exist.\n" % (app_label, opts.module_name)) print _get_contenttype_insert(opts) @@ -318,30 +318,30 @@ def database_check(mod): # Check that there aren't any *extra* permissions in the DB that the model # doesn't know about. cursor.execute("SELECT %s FROM %s WHERE %s = %%s" % \ - (db.db.quote_name('codename'), db.db.quote_name('auth_permissions'), - db.db.quote_name('package')), (app_label,)) + (backend.quote_name('codename'), backend.quote_name('auth_permissions'), + backend.quote_name('package')), (app_label,)) for row in cursor.fetchall(): try: perms_seen[row[0]] except KeyError: # sys.stderr.write("A permission called '%s.%s' was found in the database but not in the model.\n" % (app_label, row[0])) print "DELETE FROM %s WHERE %s='%s' AND %s = '%s';" % \ - (db.db.quote_name('auth_permissions'), db.db.quote_name('package'), - app_label, db.db.quote_name('codename'), row[0]) + (backend.quote_name('auth_permissions'), backend.quote_name('package'), + app_label, backend.quote_name('codename'), row[0]) # Check that there aren't any *extra* content types in the DB that the # model doesn't know about. cursor.execute("SELECT %s FROM %s WHERE %s = %%s" % \ - (db.db.quote_name('python_module_name'), db.db.quote_name('content_types'), - db.db.quote_name('package')), (app_label,)) + (backend.quote_name('python_module_name'), backend.quote_name('content_types'), + backend.quote_name('package')), (app_label,)) for row in cursor.fetchall(): try: contenttypes_seen[row[0]] except KeyError: # sys.stderr.write("A content type called '%s.%s' was found in the database but not in the model.\n" % (app_label, row[0])) print "DELETE FROM %s WHERE %s='%s' AND %s = '%s';" % \ - (db.db.quote_name('content_types'), db.db.quote_name('package'), - app_label, db.db.quote_name('python_module_name'), row[0]) + (backend.quote_name('content_types'), backend.quote_name('package'), + app_label, backend.quote_name('python_module_name'), row[0]) database_check.help_doc = "Checks that everything is installed in the database for the given model module name(s) and prints SQL statements if needed." database_check.args = APP_ARGS @@ -370,32 +370,31 @@ get_admin_index.args = APP_ARGS def init(): "Initializes the database with auth and core." try: - from django.core import db - from django.db import models + from django.db import backend, connection, models auth = models.get_app('auth') core = models.get_app('core') - cursor = db.db.cursor() + cursor = connection.cursor() for sql in get_sql_create(core) + get_sql_create(auth) + get_sql_initial_data(core) + get_sql_initial_data(auth): cursor.execute(sql) cursor.execute("INSERT INTO %s (%s, %s) VALUES ('example.com', 'Example site')" % \ - (db.db.quote_name(core.Site._meta.db_table), db.db.quote_name('domain'), - db.db.quote_name('name'))) + (backend.quote_name(core.Site._meta.db_table), backend.quote_name('domain'), + backend.quote_name('name'))) except Exception, e: import traceback sys.stderr.write("Error: The database couldn't be initialized.\n") sys.stderr.write('\n'.join(traceback.format_exception(*sys.exc_info())) + "\n") try: - db.db.rollback() + connection.rollback() except UnboundLocalError: pass sys.exit(1) else: - db.db.commit() + connection.commit() init.args = '' def install(mod): "Executes the equivalent of 'get_sql_all' in the current database." - from django.core import db + from django.db import connection from cStringIO import StringIO mod_name = mod.__name__[mod.__name__.rindex('.')+1:] @@ -410,7 +409,7 @@ def install(mod): sql_list = get_sql_all(mod) try: - cursor = db.db.cursor() + cursor = connection.cursor() for sql in sql_list: cursor.execute(sql) except Exception, e: @@ -421,9 +420,9 @@ def install(mod): Hint: Look at the output of 'django-admin.py sqlall %s'. That's the SQL this command wasn't able to run. The full error: %s\n""" % \ (mod_name, mod_name, e)) - db.db.rollback() + connection.rollback() sys.exit(1) - db.db.commit() + connection.commit() install.help_doc = "Executes ``sqlall`` for the given model module name(s) in the current database." install.args = APP_ARGS @@ -559,15 +558,17 @@ createsuperuser.args = '[username] [email] [password] (Either all or none)' def inspectdb(db_name): "Generator that introspects the tables in the given database name and returns a Django model, one line at a time." - from django.core import db + from django.db import connection, get_introspection_module from django.conf import settings + introspection_module = get_introspection_module() + def table2model(table_name): object_name = table_name.title().replace('_', '') return object_name.endswith('s') and object_name[:-1] or object_name settings.DATABASE_NAME = db_name - cursor = db.db.cursor() + cursor = connection.cursor() yield "# This is an auto-generated Django model module." yield "# You'll have to do the following manually to clean this up:" yield "# * Rearrange models' order" @@ -579,13 +580,13 @@ def inspectdb(db_name): yield '' yield 'from django.db import models' yield '' - for table_name in db.get_table_list(cursor): + for table_name in introspection_module.get_table_list(cursor): yield 'class %s(models.Model):' % table2model(table_name) try: - relations = db.get_relations(cursor, table_name) + relations = introspection_module.get_relations(cursor, table_name) except NotImplementedError: relations = {} - for i, row in enumerate(db.get_table_description(cursor, table_name)): + for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)): column_name = row[0] if relations.has_key(i): rel = relations[i] @@ -596,7 +597,7 @@ def inspectdb(db_name): field_desc = '%s = models.ForeignKey(%s, db_column=%r' % (column_name, rel_to, column_name) else: try: - field_type = db.DATA_TYPES_REVERSE[row[1]] + field_type = introspection_module.DATA_TYPES_REVERSE[row[1]] except KeyError: field_type = 'TextField' field_type_was_guessed = True @@ -786,8 +787,8 @@ runserver.args = '[optional port number, or ipaddr:port]' def createcachetable(tablename): "Creates the table needed to use the SQL cache backend" - from django.core import db - from django.db import models + from django.db import backend, get_creation_module, models + data_types = get_creation_module().DATA_TYPES fields = ( # "key" is a reserved word in MySQL, so use "cache_key" instead. models.CharField(name='cache_key', maxlength=255, unique=True, primary_key=True), @@ -797,7 +798,7 @@ def createcachetable(tablename): table_output = [] index_output = [] for f in fields: - field_output = [db.db.quote_name(f.column), db.DATA_TYPES[f.get_internal_type()] % f.__dict__] + field_output = [backend.quote_name(f.column), data_types[f.get_internal_type()] % f.__dict__] field_output.append("%sNULL" % (not f.null and "NOT " or "")) if f.unique: field_output.append("UNIQUE") @@ -806,18 +807,18 @@ def createcachetable(tablename): if f.db_index: unique = f.unique and "UNIQUE " or "" index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \ - (unique, tablename, f.column, db.db.quote_name(tablename), - db.db.quote_name(f.column))) + (unique, tablename, f.column, backend.quote_name(tablename), + backend.quote_name(f.column))) table_output.append(" ".join(field_output)) - full_statement = ["CREATE TABLE %s (" % db.db.quote_name(tablename)] + full_statement = ["CREATE TABLE %s (" % backend.quote_name(tablename)] for i, line in enumerate(table_output): full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) full_statement.append(');') - curs = db.db.cursor() + curs = connection.cursor() curs.execute("\n".join(full_statement)) for statement in index_output: curs.execute(statement) - db.db.commit() + connection.commit() createcachetable.args = "[tablename]" # Utilities for command-line script diff --git a/django/db/__init__.py b/django/db/__init__.py index 3cf3b6bbc9..8c553c52c9 100644 --- a/django/db/__init__.py +++ b/django/db/__init__.py @@ -15,5 +15,11 @@ except ImportError, e: raise ImproperlyConfigured, "Could not load database backend: %s. Is your DATABASE_ENGINE setting (currently, %r) spelled correctly? Available options are: %s" % \ (e, DATABASE_ENGINE, ", ".join(map(repr, available_backends))) +def get_introspection_module(): + return __import__('django.db.backends.%s.introspection' % DATABASE_ENGINE, '', '', ['']) + +def get_creation_module(): + return __import__('django.db.backends.%s.creation' % DATABASE_ENGINE, '', '', ['']) + connection = backend.DatabaseWrapper() -DatabaseError = dbmod.DatabaseError +DatabaseError = backend.DatabaseError diff --git a/django/db/backends/ado_mssql/base.py b/django/db/backends/ado_mssql/base.py index 2c854ee811..982cea40a0 100644 --- a/django/db/backends/ado_mssql/base.py +++ b/django/db/backends/ado_mssql/base.py @@ -76,10 +76,10 @@ class DatabaseWrapper: self.connection.close() self.connection = None - def quote_name(self, name): - if name.startswith('[') and name.endswith(']'): - return name # Quoting once is enough. - return '[%s]' % name +def quote_name(name): + if name.startswith('[') and name.endswith(']'): + return name # Quoting once is enough. + return '[%s]' % name dictfetchone = util.dictfetchone dictfetchmany = util.dictfetchmany @@ -127,30 +127,3 @@ OPERATOR_MAPPING = { 'istartswith': 'LIKE %s', 'iendswith': 'LIKE %s', } - -DATA_TYPES = { - 'AutoField': 'int IDENTITY (1, 1)', - 'BooleanField': 'bit', - 'CharField': 'varchar(%(maxlength)s)', - 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', - 'DateField': 'smalldatetime', - 'DateTimeField': 'smalldatetime', - 'FileField': 'varchar(100)', - 'FilePathField': 'varchar(100)', - 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)', - 'ImageField': 'varchar(100)', - 'IntegerField': 'int', - 'IPAddressField': 'char(15)', - 'ManyToManyField': None, - 'NullBooleanField': 'bit', - 'OneToOneField': 'int', - 'PhoneNumberField': 'varchar(20)', - 'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)', - 'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)', - 'SlugField': 'varchar(50)', - 'SmallIntegerField': 'smallint', - 'TextField': 'text', - 'TimeField': 'time', - 'URLField': 'varchar(200)', - 'USStateField': 'varchar(2)', -} diff --git a/django/db/backends/ado_mssql/creation.py b/django/db/backends/ado_mssql/creation.py new file mode 100644 index 0000000000..493512f1fb --- /dev/null +++ b/django/db/backends/ado_mssql/creation.py @@ -0,0 +1,26 @@ +DATA_TYPES = { + 'AutoField': 'int IDENTITY (1, 1)', + 'BooleanField': 'bit', + 'CharField': 'varchar(%(maxlength)s)', + 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', + 'DateField': 'smalldatetime', + 'DateTimeField': 'smalldatetime', + 'FileField': 'varchar(100)', + 'FilePathField': 'varchar(100)', + 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)', + 'ImageField': 'varchar(100)', + 'IntegerField': 'int', + 'IPAddressField': 'char(15)', + 'ManyToManyField': None, + 'NullBooleanField': 'bit', + 'OneToOneField': 'int', + 'PhoneNumberField': 'varchar(20)', + 'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)', + 'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)', + 'SlugField': 'varchar(50)', + 'SmallIntegerField': 'smallint', + 'TextField': 'text', + 'TimeField': 'time', + 'URLField': 'varchar(200)', + 'USStateField': 'varchar(2)', +} diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index 3d4e0e9ff6..32476c0f7b 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -83,10 +83,10 @@ class DatabaseWrapper: self.connection.close() self.connection = None - def quote_name(self, name): - if name.startswith("`") and name.endswith("`"): - return name # Quoting once is enough. - return "`%s`" % name +def quote_name(name): + if name.startswith("`") and name.endswith("`"): + return name # Quoting once is enough. + return "`%s`" % name dictfetchone = util.dictfetchone dictfetchmany = util.dictfetchmany @@ -137,34 +137,3 @@ OPERATOR_MAPPING = { 'istartswith': 'LIKE %s', 'iendswith': 'LIKE %s', } - -# This dictionary maps Field objects to their associated MySQL column -# types, as strings. Column-type strings can contain format strings; they'll -# be interpolated against the values of Field.__dict__ before being output. -# If a column type is set to None, it won't be included in the output. -DATA_TYPES = { - 'AutoField': 'mediumint(9) unsigned auto_increment', - 'BooleanField': 'bool', - 'CharField': 'varchar(%(maxlength)s)', - 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', - 'DateField': 'date', - 'DateTimeField': 'datetime', - 'FileField': 'varchar(100)', - 'FilePathField': 'varchar(100)', - 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)', - 'ImageField': 'varchar(100)', - 'IntegerField': 'integer', - 'IPAddressField': 'char(15)', - 'ManyToManyField': None, - 'NullBooleanField': 'bool', - 'OneToOneField': 'integer', - 'PhoneNumberField': 'varchar(20)', - 'PositiveIntegerField': 'integer UNSIGNED', - 'PositiveSmallIntegerField': 'smallint UNSIGNED', - 'SlugField': 'varchar(50)', - 'SmallIntegerField': 'smallint', - 'TextField': 'longtext', - 'TimeField': 'time', - 'URLField': 'varchar(200)', - 'USStateField': 'varchar(2)', -} diff --git a/django/db/backends/mysql/creation.py b/django/db/backends/mysql/creation.py new file mode 100644 index 0000000000..4a29c18b13 --- /dev/null +++ b/django/db/backends/mysql/creation.py @@ -0,0 +1,30 @@ +# This dictionary maps Field objects to their associated MySQL column +# types, as strings. Column-type strings can contain format strings; they'll +# be interpolated against the values of Field.__dict__ before being output. +# If a column type is set to None, it won't be included in the output. +DATA_TYPES = { + 'AutoField': 'mediumint(9) unsigned auto_increment', + 'BooleanField': 'bool', + 'CharField': 'varchar(%(maxlength)s)', + 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', + 'DateField': 'date', + 'DateTimeField': 'datetime', + 'FileField': 'varchar(100)', + 'FilePathField': 'varchar(100)', + 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)', + 'ImageField': 'varchar(100)', + 'IntegerField': 'integer', + 'IPAddressField': 'char(15)', + 'ManyToManyField': None, + 'NullBooleanField': 'bool', + 'OneToOneField': 'integer', + 'PhoneNumberField': 'varchar(20)', + 'PositiveIntegerField': 'integer UNSIGNED', + 'PositiveSmallIntegerField': 'smallint UNSIGNED', + 'SlugField': 'varchar(50)', + 'SmallIntegerField': 'smallint', + 'TextField': 'longtext', + 'TimeField': 'time', + 'URLField': 'varchar(200)', + 'USStateField': 'varchar(2)', +} diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index 8d57e7e21e..482fa2a5f7 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -49,10 +49,10 @@ class DatabaseWrapper: self.connection.close() self.connection = None - def quote_name(self, name): - if name.startswith('"') and name.endswith('"'): - return name # Quoting once is enough. - return '"%s"' % name +def quote_name(name): + if name.startswith('"') and name.endswith('"'): + return name # Quoting once is enough. + return '"%s"' % name def dictfetchone(cursor): "Returns a row from the cursor as a dict" @@ -115,34 +115,3 @@ OPERATOR_MAPPING = { 'istartswith': 'ILIKE %s', 'iendswith': 'ILIKE %s', } - -# This dictionary maps Field objects to their associated PostgreSQL column -# types, as strings. Column-type strings can contain format strings; they'll -# be interpolated against the values of Field.__dict__ before being output. -# If a column type is set to None, it won't be included in the output. -DATA_TYPES = { - 'AutoField': 'serial', - 'BooleanField': 'boolean', - 'CharField': 'varchar(%(maxlength)s)', - 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', - 'DateField': 'date', - 'DateTimeField': 'timestamp with time zone', - 'FileField': 'varchar(100)', - 'FilePathField': 'varchar(100)', - 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)', - 'ImageField': 'varchar(100)', - 'IntegerField': 'integer', - 'IPAddressField': 'inet', - 'ManyToManyField': None, - 'NullBooleanField': 'boolean', - 'OneToOneField': 'integer', - 'PhoneNumberField': 'varchar(20)', - 'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)', - 'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)', - 'SlugField': 'varchar(50)', - 'SmallIntegerField': 'smallint', - 'TextField': 'text', - 'TimeField': 'time', - 'URLField': 'varchar(200)', - 'USStateField': 'varchar(2)', -} diff --git a/django/db/backends/postgresql/creation.py b/django/db/backends/postgresql/creation.py new file mode 100644 index 0000000000..accc383330 --- /dev/null +++ b/django/db/backends/postgresql/creation.py @@ -0,0 +1,30 @@ +# This dictionary maps Field objects to their associated PostgreSQL column +# types, as strings. Column-type strings can contain format strings; they'll +# be interpolated against the values of Field.__dict__ before being output. +# If a column type is set to None, it won't be included in the output. +DATA_TYPES = { + 'AutoField': 'serial', + 'BooleanField': 'boolean', + 'CharField': 'varchar(%(maxlength)s)', + 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', + 'DateField': 'date', + 'DateTimeField': 'timestamp with time zone', + 'FileField': 'varchar(100)', + 'FilePathField': 'varchar(100)', + 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)', + 'ImageField': 'varchar(100)', + 'IntegerField': 'integer', + 'IPAddressField': 'inet', + 'ManyToManyField': None, + 'NullBooleanField': 'boolean', + 'OneToOneField': 'integer', + 'PhoneNumberField': 'varchar(20)', + 'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)', + 'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)', + 'SlugField': 'varchar(50)', + 'SmallIntegerField': 'smallint', + 'TextField': 'text', + 'TimeField': 'time', + 'URLField': 'varchar(200)', + 'USStateField': 'varchar(2)', +} diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 047a1ddfc7..1ab9f835e6 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -54,10 +54,10 @@ class DatabaseWrapper: self.connection.close() self.connection = None - def quote_name(self, name): - if name.startswith('"') and name.endswith('"'): - return name # Quoting once is enough. - return '"%s"' % name +def quote_name(name): + if name.startswith('"') and name.endswith('"'): + return name # Quoting once is enough. + return '"%s"' % name dictfetchone = util.dictfetchone dictfetchmany = util.dictfetchmany @@ -146,33 +146,3 @@ OPERATOR_MAPPING = { 'istartswith': "LIKE %s ESCAPE '\\'", 'iendswith': "LIKE %s ESCAPE '\\'", } - -# SQLite doesn't actually support most of these types, but it "does the right -# thing" given more verbose field definitions, so leave them as is so that -# schema inspection is more useful. -DATA_TYPES = { - 'AutoField': 'integer', - 'BooleanField': 'bool', - 'CharField': 'varchar(%(maxlength)s)', - 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', - 'DateField': 'date', - 'DateTimeField': 'datetime', - 'FileField': 'varchar(100)', - 'FilePathField': 'varchar(100)', - 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)', - 'ImageField': 'varchar(100)', - 'IntegerField': 'integer', - 'IPAddressField': 'char(15)', - 'ManyToManyField': None, - 'NullBooleanField': 'bool', - 'OneToOneField': 'integer', - 'PhoneNumberField': 'varchar(20)', - 'PositiveIntegerField': 'integer unsigned', - 'PositiveSmallIntegerField': 'smallint unsigned', - 'SlugField': 'varchar(50)', - 'SmallIntegerField': 'smallint', - 'TextField': 'text', - 'TimeField': 'time', - 'URLField': 'varchar(200)', - 'USStateField': 'varchar(2)', -} diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py new file mode 100644 index 0000000000..945ae0c477 --- /dev/null +++ b/django/db/backends/sqlite3/creation.py @@ -0,0 +1,29 @@ +# SQLite doesn't actually support most of these types, but it "does the right +# thing" given more verbose field definitions, so leave them as is so that +# schema inspection is more useful. +DATA_TYPES = { + 'AutoField': 'integer', + 'BooleanField': 'bool', + 'CharField': 'varchar(%(maxlength)s)', + 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', + 'DateField': 'date', + 'DateTimeField': 'datetime', + 'FileField': 'varchar(100)', + 'FilePathField': 'varchar(100)', + 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)', + 'ImageField': 'varchar(100)', + 'IntegerField': 'integer', + 'IPAddressField': 'char(15)', + 'ManyToManyField': None, + 'NullBooleanField': 'bool', + 'OneToOneField': 'integer', + 'PhoneNumberField': 'varchar(20)', + 'PositiveIntegerField': 'integer unsigned', + 'PositiveSmallIntegerField': 'smallint unsigned', + 'SlugField': 'varchar(50)', + 'SmallIntegerField': 'smallint', + 'TextField': 'text', + 'TimeField': 'time', + 'URLField': 'varchar(200)', + 'USStateField': 'varchar(2)', +} diff --git a/django/db/models/__init__.py b/django/db/models/__init__.py index 9a7401039d..9800de2bbf 100644 --- a/django/db/models/__init__.py +++ b/django/db/models/__init__.py @@ -1,7 +1,7 @@ from django.conf import settings from django.core import formfields, validators -from django.core import db from django.core.exceptions import ObjectDoesNotExist +from django.db import backend, connection from django.db.models.fields import * from django.utils.functional import curry from django.utils.text import capfirst @@ -58,15 +58,15 @@ def orderfield2column(f, opts): def orderlist2sql(order_list, opts, prefix=''): if prefix.endswith('.'): - prefix = db.db.quote_name(prefix[:-1]) + '.' + prefix = backend.quote_name(prefix[:-1]) + '.' output = [] for f in handle_legacy_orderlist(order_list): if f.startswith('-'): - output.append('%s%s DESC' % (prefix, db.db.quote_name(orderfield2column(f[1:], opts)))) + output.append('%s%s DESC' % (prefix, backend.quote_name(orderfield2column(f[1:], opts)))) elif f == '?': - output.append(db.get_random_function_sql()) + output.append(backend.get_random_function_sql()) else: - output.append('%s%s ASC' % (prefix, db.db.quote_name(orderfield2column(f, opts)))) + output.append('%s%s ASC' % (prefix, backend.quote_name(orderfield2column(f, opts)))) return ', '.join(output) def get_module(app_label, module_name): @@ -536,24 +536,6 @@ class Options: self._field_types[field_type] = False return self._field_types[field_type] -def _reassign_globals(function_dict, extra_globals, namespace): - new_functions = {} - for k, v in function_dict.items(): - # Get the code object. - code = v.func_code - # Recreate the function, but give it access to extra_globals and the - # given namespace's globals, too. - new_globals = {'__builtins__': __builtins__, 'db': db.db, 'datetime': datetime} - new_globals.update(extra_globals.__dict__) - func = types.FunctionType(code, globals=new_globals, name=k, argdefs=v.func_defaults) - func.__dict__.update(v.__dict__) - setattr(namespace, k, func) - # For all of the custom functions that have been added so far, give - # them access to the new function we've just created. - for new_k, new_v in new_functions.items(): - new_v.func_globals[k] = func - new_functions[k] = func - # Calculate the module_name using a poor-man's pluralization. get_module_name = lambda class_name: class_name.lower() + 's' @@ -582,12 +564,12 @@ class Manager(object): if ' ' in word: return word else: - return db.db.quote_name(word) + return backend.quote_name(word) opts = self.klass._meta # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. - select = ["%s.%s" % (db.db.quote_name(opts.db_table), db.db.quote_name(f.column)) for f in opts.fields] + select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields] tables = [opts.db_table] + (kwargs.get('tables') and kwargs['tables'][:] or []) tables = [quote_only_if_word(t) for t in tables] where = kwargs.get('where') and kwargs['where'][:] or [] @@ -608,13 +590,13 @@ class Manager(object): # Add any additional SELECTs passed in via kwargs. if kwargs.get('select'): - select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), db.db.quote_name(s[0])) for s in kwargs['select']]) + select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in kwargs['select']]) # ORDER BY clause order_by = [] for f in handle_legacy_orderlist(kwargs.get('order_by', opts.ordering)): if f == '?': # Special case. - order_by.append(db.get_random_function_sql()) + order_by.append(backend.get_random_function_sql()) else: if f.startswith('-'): col_name = f[1:] @@ -624,20 +606,20 @@ class Manager(object): order = "ASC" if "." in col_name: table_prefix, col_name = col_name.split('.', 1) - table_prefix = db.db.quote_name(table_prefix) + '.' + table_prefix = backend.quote_name(table_prefix) + '.' else: # Use the database table as a column prefix if it wasn't given, # and if the requested column isn't a custom SELECT. if "." not in col_name and col_name not in [k[0] for k in kwargs.get('select', [])]: - table_prefix = db.db.quote_name(opts.db_table) + '.' + table_prefix = backend.quote_name(opts.db_table) + '.' else: table_prefix = '' - order_by.append('%s%s %s' % (table_prefix, db.db.quote_name(orderfield2column(col_name, opts)), order)) + order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order)) order_by = ", ".join(order_by) # LIMIT and OFFSET clauses if kwargs.get('limit') is not None: - limit_sql = " %s " % db.get_limit_offset_sql(kwargs['limit'], kwargs.get('offset')) + limit_sql = " %s " % backend.get_limit_offset_sql(kwargs['limit'], kwargs.get('offset')) else: assert kwargs.get('offset') is None, "'offset' is not allowed without 'limit'" limit_sql = "" @@ -649,7 +631,7 @@ class Manager(object): # undefined, so we convert it to a list of tuples internally. kwargs['select'] = kwargs.get('select', {}).items() - cursor = db.db.cursor() + cursor = connection.cursor() select, sql, params = self._get_sql_clause(**kwargs) cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params) fill_cache = kwargs.get('select_related') @@ -676,7 +658,7 @@ class Manager(object): kwargs['limit'] = None kwargs['select_related'] = False _, sql, params = self._get_sql_clause(**kwargs) - cursor = db.db.cursor() + cursor = connection.cursor() cursor.execute("SELECT COUNT(*)" + sql, params) return cursor.fetchone()[0] @@ -690,7 +672,7 @@ class Manager(object): def get_in_bulk(self, *args, **kwargs): id_list = args and args[0] or kwargs['id_list'] assert id_list != [], "get_in_bulk() cannot be passed an empty list." - kwargs['where'] = ["%s.%s IN (%s)" % (db.db.quote_name(self.klass._meta.db_table), db.db.quote_name(self.klass._meta.pk.column), ",".join(['%s'] * len(id_list)))] + kwargs['where'] = ["%s.%s IN (%s)" % (backend.quote_name(self.klass._meta.db_table), backend.quote_name(self.klass._meta.pk.column), ",".join(['%s'] * len(id_list)))] kwargs['params'] = id_list obj_list = self.get_list(**kwargs) return dict([(getattr(o, self.klass._meta.pk.attname), o) for o in obj_list]) @@ -706,9 +688,9 @@ class Manager(object): except KeyError: # Default to all fields. fields = [f.column for f in self.klass._meta.fields] - cursor = db.db.cursor() + cursor = connection.cursor() _, sql, params = self._get_sql_clause(**kwargs) - select = ['%s.%s' % (db.db.quote_name(self.klass._meta.db_table), db.db.quote_name(f)) for f in fields] + select = ['%s.%s' % (backend.quote_name(self.klass._meta.db_table), backend.quote_name(f)) for f in fields] cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params) while 1: rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) @@ -726,7 +708,7 @@ class Manager(object): return self.get_object(**kwargs) def __get_date_list(self, field, *args, **kwargs): - from django.core.db.typecasts import typecast_timestamp + from django.db.backends.util import typecast_timestamp kind = args and args[0] or kwargs['kind'] assert kind in ("month", "year", "day"), "'kind' must be one of 'year', 'month' or 'day'." order = 'ASC' @@ -737,12 +719,12 @@ class Manager(object): kwargs['order_by'] = () # Clear this because it'll mess things up otherwise. if field.null: kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \ - (db.db.quote_name(self.klass._meta.db_table), db.db.quote_name(field.column))) + (backend.quote_name(self.klass._meta.db_table), backend.quote_name(field.column))) select, sql, params = self._get_sql_clause(**kwargs) sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \ - (db.get_date_trunc_sql(kind, '%s.%s' % (db.db.quote_name(self.klass._meta.db_table), - db.db.quote_name(field.column))), sql, order) - cursor = db.db.cursor() + (backend.get_date_trunc_sql(kind, '%s.%s' % (backend.quote_name(self.klass._meta.db_table), + backend.quote_name(field.column))), sql, order) + cursor = connection.cursor() cursor.execute(sql, params) # We have to manually run typecast_timestamp(str()) on the results, because # MySQL doesn't automatically cast the result of date functions as datetime @@ -969,7 +951,7 @@ class Model(object): self._pre_save() non_pks = [f for f in self._meta.fields if not f.primary_key] - cursor = db.db.cursor() + cursor = connection.cursor() # First, try an UPDATE. If that doesn't update anything, do an INSERT. pk_val = getattr(self, self._meta.pk.attname) @@ -978,19 +960,19 @@ class Model(object): if pk_set: # Determine whether a record with the primary key already exists. cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % \ - (db.db.quote_name(self._meta.db_table), db.db.quote_name(self._meta.pk.column)), [pk_val]) + (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val]) # If it does already exist, do an UPDATE. if cursor.fetchone(): db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.attname), False)) for f in non_pks] cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \ - (db.db.quote_name(self._meta.db_table), - ','.join(['%s=%%s' % db.db.quote_name(f.column) for f in non_pks]), - db.db.quote_name(self._meta.pk.attname)), + (backend.quote_name(self._meta.db_table), + ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]), + backend.quote_name(self._meta.pk.attname)), db_values + [pk_val]) else: record_exists = False if not pk_set or not record_exists: - field_names = [db.db.quote_name(f.column) for f in self._meta.fields if not isinstance(f, AutoField)] + field_names = [backend.quote_name(f.column) for f in self._meta.fields if not isinstance(f, AutoField)] db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.attname), True)) for f in self._meta.fields if not isinstance(f, AutoField)] # If the PK has been manually set, respect that. if pk_set: @@ -998,17 +980,17 @@ class Model(object): db_values += [f.get_db_prep_save(f.pre_save(getattr(self, f.column), True)) for f in self._meta.fields if isinstance(f, AutoField)] placeholders = ['%s'] * len(field_names) if self._meta.order_with_respect_to: - field_names.append(db.db.quote_name('_order')) + field_names.append(backend.quote_name('_order')) # TODO: This assumes the database supports subqueries. placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \ - (db.db.quote_name(self._meta.db_table), db.db.quote_name(self._meta.order_with_respect_to.column))) + (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column))) db_values.append(getattr(self, self._meta.order_with_respect_to.attname)) cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ - (db.db.quote_name(self._meta.db_table), ','.join(field_names), + (backend.quote_name(self._meta.db_table), ','.join(field_names), ','.join(placeholders)), db_values) if self._meta.has_auto_field and not pk_set: - setattr(self, self._meta.pk.attname, db.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column)) - db.db.commit() + setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column)) + connection.commit() # Run any post-save hooks. if hasattr(self, '_post_save'): @@ -1023,7 +1005,7 @@ class Model(object): if hasattr(self, '_pre_delete'): self._pre_delete() - cursor = db.db.cursor() + cursor = connection.cursor() for related in self._meta.get_all_related_objects(): rel_opts_name = related.get_method_name_part() if isinstance(related.field.rel, OneToOne): @@ -1038,17 +1020,17 @@ class Model(object): sub_obj.delete() for related in self._meta.get_all_related_many_to_many_objects(): cursor.execute("DELETE FROM %s WHERE %s=%%s" % \ - (db.db.quote_name(related.field.get_m2m_db_table(related.opts)), - db.db.quote_name(self._meta.object_name.lower() + '_id')), [getattr(self, self._meta.pk.attname)]) + (backend.quote_name(related.field.get_m2m_db_table(related.opts)), + backend.quote_name(self._meta.object_name.lower() + '_id')), [getattr(self, self._meta.pk.attname)]) for f in self._meta.many_to_many: cursor.execute("DELETE FROM %s WHERE %s=%%s" % \ - (db.db.quote_name(f.get_m2m_db_table(self._meta)), - db.db.quote_name(self._meta.object_name.lower() + '_id')), + (backend.quote_name(f.get_m2m_db_table(self._meta)), + backend.quote_name(self._meta.object_name.lower() + '_id')), [getattr(self, self._meta.pk.attname)]) cursor.execute("DELETE FROM %s WHERE %s=%%s" % \ - (db.db.quote_name(self._meta.db_table), db.db.quote_name(self._meta.pk.column)), + (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [getattr(self, self._meta.pk.attname)]) - db.db.commit() + connection.commit() setattr(self, self._meta.pk.attname, None) for f in self._meta.fields: if isinstance(f, FileField) and getattr(self, f.attname): @@ -1071,8 +1053,8 @@ class Model(object): def __get_next_or_previous_by_FIELD(self, field, is_next, **kwargs): op = is_next and '>' or '<' kwargs.setdefault('where', []).append('(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \ - (db.db.quote_name(field.column), op, db.db.quote_name(field.column), - db.db.quote_name(self._meta.db_table), db.db.quote_name(self._meta.pk.column), op)) + (backend.quote_name(field.column), op, backend.quote_name(field.column), + backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column), op)) param = str(getattr(self, field.attname)) kwargs.setdefault('params', []).extend([param, param, getattr(self, self._meta.pk.attname)]) kwargs['order_by'] = [(not is_next and '-' or '') + field.name, (not is_next and '-' or '') + self._meta.pk.name] @@ -1086,9 +1068,9 @@ class Model(object): order_field = self.order_with_respect_to obj = self.objects.get_object(order_by=('_order',), where=['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \ - (db.db.quote_name('_order'), op, db.db.quote_name('_order'), - db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column)), - '%s=%%s' % db.db.quote_name(order_field.column)], + (backend.quote_name('_order'), op, backend.quote_name('_order'), + backend.quote_name(opts.db_table), backend.quote_name(opts.pk.column)), + '%s=%%s' % backend.quote_name(order_field.column)], limit=1, params=[getattr(self, opts.pk.attname), getattr(self, order_field.attname)]) setattr(self, cachename, obj) @@ -1180,13 +1162,13 @@ class Model(object): if not hasattr(self, cache_var): rel_opts = field_with_rel.rel.to._meta sql = "SELECT %s FROM %s a, %s b WHERE a.%s = b.%s AND b.%s = %%s %s" % \ - (','.join(['a.%s' % db.db.quote_name(f.column) for f in rel_opts.fields]), - db.db.quote_name(rel_opts.db_table), - db.db.quote_name(field_with_rel.get_m2m_db_table(self._meta)), - db.db.quote_name(rel_opts.pk.column), - db.db.quote_name(rel_opts.object_name.lower() + '_id'), - db.db.quote_name(self._meta.object_name.lower() + '_id'), rel_opts.get_order_sql('a')) - cursor = db.db.cursor() + (','.join(['a.%s' % backend.quote_name(f.column) for f in rel_opts.fields]), + backend.quote_name(rel_opts.db_table), + backend.quote_name(field_with_rel.get_m2m_db_table(self._meta)), + backend.quote_name(rel_opts.pk.column), + backend.quote_name(rel_opts.object_name.lower() + '_id'), + backend.quote_name(self._meta.object_name.lower() + '_id'), rel_opts.get_order_sql('a')) + cursor = connection.cursor() cursor.execute(sql, [getattr(self, self._meta.pk.attname)]) setattr(self, cache_var, [field_with_rel.rel.to(*row) for row in cursor.fetchall()]) return getattr(self, cache_var) @@ -1205,21 +1187,21 @@ class Model(object): return False # No change rel = field_with_rel.rel.to._meta m2m_table = field_with_rel.get_m2m_db_table(self._meta) - cursor = db.db.cursor() + cursor = connection.cursor() this_id = getattr(self, self._meta.pk.attname) if ids_to_delete: sql = "DELETE FROM %s WHERE %s = %%s AND %s IN (%s)" % \ - (db.db.quote_name(m2m_table), - db.db.quote_name(self._meta.object_name.lower() + '_id'), - db.db.quote_name(rel.object_name.lower() + '_id'), ','.join(map(str, ids_to_delete))) + (backend.quote_name(m2m_table), + backend.quote_name(self._meta.object_name.lower() + '_id'), + backend.quote_name(rel.object_name.lower() + '_id'), ','.join(map(str, ids_to_delete))) cursor.execute(sql, [this_id]) if ids_to_add: sql = "INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \ - (db.db.quote_name(m2m_table), - db.db.quote_name(self._meta.object_name.lower() + '_id'), - db.db.quote_name(rel.object_name.lower() + '_id')) + (backend.quote_name(m2m_table), + backend.quote_name(self._meta.object_name.lower() + '_id'), + backend.quote_name(rel.object_name.lower() + '_id')) cursor.executemany(sql, [(this_id, i) for i in ids_to_add]) - db.db.commit() + connection.commit() try: delattr(self, '_%s_cache' % field_with_rel.name) # clear cache, if it exists except AttributeError: @@ -1265,38 +1247,38 @@ def method_set_related_many_to_many(rel_opts, rel_field, self, id_list): rel = rel_field.rel.to m2m_table = rel_field.get_m2m_db_table(rel_opts) this_id = getattr(self, self._meta.pk.attname) - cursor = db.db.cursor() + cursor = connection.cursor() cursor.execute("DELETE FROM %s WHERE %s = %%s" % \ - (db.db.quote_name(m2m_table), - db.db.quote_name(rel.object_name.lower() + '_id')), [this_id]) + (backend.quote_name(m2m_table), + backend.quote_name(rel.object_name.lower() + '_id')), [this_id]) sql = "INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \ - (db.db.quote_name(m2m_table), - db.db.quote_name(rel.object_name.lower() + '_id'), - db.db.quote_name(rel_opts.object_name.lower() + '_id')) + (backend.quote_name(m2m_table), + backend.quote_name(rel.object_name.lower() + '_id'), + backend.quote_name(rel_opts.object_name.lower() + '_id')) cursor.executemany(sql, [(this_id, i) for i in id_list]) - db.db.commit() + connection.commit() # ORDERING METHODS ######################### def method_set_order(ordered_obj, self, id_list): - cursor = db.db.cursor() + cursor = connection.cursor() # Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s" sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \ - (db.db.quote_name(ordered_obj.db_table), db.db.quote_name('_order'), - db.db.quote_name(ordered_obj.order_with_respect_to.column), - db.db.quote_name(ordered_obj.pk.column)) + (backend.quote_name(ordered_obj.db_table), backend.quote_name('_order'), + backend.quote_name(ordered_obj.order_with_respect_to.column), + backend.quote_name(ordered_obj.pk.column)) rel_val = getattr(self, ordered_obj.order_with_respect_to.rel.field_name) cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)]) - db.db.commit() + connection.commit() def method_get_order(ordered_obj, self): - cursor = db.db.cursor() + cursor = connection.cursor() # Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order" sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \ - (db.db.quote_name(ordered_obj.pk.column), - db.db.quote_name(ordered_obj.db_table), - db.db.quote_name(ordered_obj.order_with_respect_to.column), - db.db.quote_name('_order')) + (backend.quote_name(ordered_obj.pk.column), + backend.quote_name(ordered_obj.db_table), + backend.quote_name(ordered_obj.order_with_respect_to.column), + backend.quote_name('_order')) rel_val = getattr(self, ordered_obj.order_with_respect_to.rel.field_name) cursor.execute(sql, [rel_val]) return [r[0] for r in cursor.fetchall()] @@ -1310,10 +1292,10 @@ def get_absolute_url(opts, func, self): def _get_where_clause(lookup_type, table_prefix, field_name, value): if table_prefix.endswith('.'): - table_prefix = db.db.quote_name(table_prefix[:-1])+'.' - field_name = db.db.quote_name(field_name) + table_prefix = backend.quote_name(table_prefix[:-1])+'.' + field_name = backend.quote_name(field_name) try: - return '%s%s %s' % (table_prefix, field_name, (db.OPERATOR_MAPPING[lookup_type] % '%s')) + return '%s%s %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s')) except KeyError: pass if lookup_type == 'in': @@ -1321,7 +1303,7 @@ def _get_where_clause(lookup_type, table_prefix, field_name, value): elif lookup_type in ('range', 'year'): return '%s%s BETWEEN %%s AND %%s' % (table_prefix, field_name) elif lookup_type in ('month', 'day'): - return "%s = %%s" % db.get_date_extract_sql(lookup_type, table_prefix + field_name) + return "%s = %%s" % backend.get_date_extract_sql(lookup_type, table_prefix + field_name) elif lookup_type == 'isnull': return "%s%s IS %sNULL" % (table_prefix, field_name, (not value and 'NOT ' or '')) raise TypeError, "Got invalid lookup_type: %s" % repr(lookup_type) @@ -1345,16 +1327,16 @@ def _fill_table_cache(opts, select, tables, where, old_prefix, cache_tables_seen if f.rel and not f.null: db_table = f.rel.to._meta.db_table if db_table not in cache_tables_seen: - tables.append(db.db.quote_name(db_table)) + tables.append(backend.quote_name(db_table)) else: # The table was already seen, so give it a table alias. new_prefix = '%s%s' % (db_table, len(cache_tables_seen)) - tables.append('%s %s' % (db.db.quote_name(db_table), db.db.quote_name(new_prefix))) + tables.append('%s %s' % (backend.quote_name(db_table), backend.quote_name(new_prefix))) db_table = new_prefix cache_tables_seen.append(db_table) where.append('%s.%s = %s.%s' % \ - (db.db.quote_name(old_prefix), db.db.quote_name(f.column), - db.db.quote_name(db_table), db.db.quote_name(f.rel.get_related_field().column))) - select.extend(['%s.%s' % (db.db.quote_name(db_table), db.db.quote_name(f2.column)) for f2 in f.rel.to._meta.fields]) + (backend.quote_name(old_prefix), backend.quote_name(f.column), + backend.quote_name(db_table), backend.quote_name(f.rel.get_related_field().column))) + select.extend(['%s.%s' % (backend.quote_name(db_table), backend.quote_name(f2.column)) for f2 in f.rel.to._meta.fields]) _fill_table_cache(f.rel.to._meta, select, tables, where, db_table, cache_tables_seen) def _throw_bad_kwarg_error(kwarg): @@ -1420,15 +1402,15 @@ def _parse_lookup(kwarg_items, opts, table_count=0): # Try many-to-many relationships first... for f in current_opts.many_to_many: if f.name == current: - rel_table_alias = db.db.quote_name('t%s' % table_count) + rel_table_alias = backend.quote_name('t%s' % table_count) table_count += 1 tables.append('%s %s' % \ - (db.db.quote_name(f.get_m2m_db_table(current_opts)), rel_table_alias)) + (backend.quote_name(f.get_m2m_db_table(current_opts)), rel_table_alias)) join_where.append('%s.%s = %s.%s' % \ - (db.db.quote_name(current_table_alias), - db.db.quote_name(current_opts.pk.column), + (backend.quote_name(current_table_alias), + backend.quote_name(current_opts.pk.column), rel_table_alias, - db.db.quote_name(current_opts.object_name.lower() + '_id'))) + backend.quote_name(current_opts.object_name.lower() + '_id'))) # Optimization: In the case of primary-key lookups, we # don't have to do an extra join. if lookup_list and lookup_list[0] == f.rel.to._meta.pk.name and lookup_type == 'exact': @@ -1439,13 +1421,13 @@ def _parse_lookup(kwarg_items, opts, table_count=0): param_required = False else: new_table_alias = 't%s' % table_count - tables.append('%s %s' % (db.db.quote_name(f.rel.to._meta.db_table), - db.db.quote_name(new_table_alias))) + tables.append('%s %s' % (backend.quote_name(f.rel.to._meta.db_table), + backend.quote_name(new_table_alias))) join_where.append('%s.%s = %s.%s' % \ - (db.db.quote_name(rel_table_alias), - db.db.quote_name(f.rel.to._meta.object_name.lower() + '_id'), - db.db.quote_name(new_table_alias), - db.db.quote_name(f.rel.to._meta.pk.column))) + (backend.quote_name(rel_table_alias), + backend.quote_name(f.rel.to._meta.object_name.lower() + '_id'), + backend.quote_name(new_table_alias), + backend.quote_name(f.rel.to._meta.pk.column))) current_table_alias = new_table_alias param_required = True current_opts = f.rel.to._meta @@ -1469,10 +1451,10 @@ def _parse_lookup(kwarg_items, opts, table_count=0): else: new_table_alias = 't%s' % table_count tables.append('%s %s' % \ - (db.db.quote_name(f.rel.to._meta.db_table), db.db.quote_name(new_table_alias))) + (backend.quote_name(f.rel.to._meta.db_table), backend.quote_name(new_table_alias))) join_where.append('%s.%s = %s.%s' % \ - (db.db.quote_name(current_table_alias), db.db.quote_name(f.column), - db.db.quote_name(new_table_alias), db.db.quote_name(f.rel.to._meta.pk.column))) + (backend.quote_name(current_table_alias), backend.quote_name(f.column), + backend.quote_name(new_table_alias), backend.quote_name(f.rel.to._meta.pk.column))) current_table_alias = new_table_alias param_required = True current_opts = f.rel.to._meta diff --git a/tests/modeltests/custom_methods/models.py b/tests/modeltests/custom_methods/models.py index 56512a20b0..bd1c5f7303 100644 --- a/tests/modeltests/custom_methods/models.py +++ b/tests/modeltests/custom_methods/models.py @@ -24,8 +24,8 @@ class Article(models.Model): Verbose version of get_articles_from_same_day_1, which does a custom database query for the sake of demonstration. """ - from django.core.db import db - cursor = db.cursor() + from django.db import connection + cursor = connection.cursor() cursor.execute(""" SELECT id, headline, pub_date FROM custom_methods_articles diff --git a/tests/othertests/db_typecasts.py b/tests/othertests/db_typecasts.py index 52cab666de..ffc9b34aec 100644 --- a/tests/othertests/db_typecasts.py +++ b/tests/othertests/db_typecasts.py @@ -1,6 +1,6 @@ -# Unit tests for django.core.db.typecasts +# Unit tests for typecast functions in django.db.backends.util -from django.core.db import typecasts +from django.db.backends import util as typecasts import datetime TEST_CASES = { diff --git a/tests/runtests.py b/tests/runtests.py index 98a7071962..ae5091b345 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -68,7 +68,7 @@ class TestRunner: # Manually set INSTALLED_APPS to point to the test models. settings.INSTALLED_APPS = [MODEL_TESTS_DIR_NAME + '.' + a for a in get_test_models()] - from django.core.db import db + from django.db import connection from django.core import management # Determine which models we're going to test. @@ -93,9 +93,9 @@ class TestRunner: # Create the test database and connect to it. We need autocommit() # because PostgreSQL doesn't allow CREATE DATABASE statements # within transactions. - cursor = db.cursor() + cursor = connection.cursor() try: - db.connection.autocommit(1) + connection.connection.autocommit(1) except AttributeError: pass self.output(1, "Creating test database") @@ -110,12 +110,12 @@ class TestRunner: else: print "Tests cancelled." return - db.close() + connection.close() old_database_name = settings.DATABASE_NAME settings.DATABASE_NAME = TEST_DATABASE_NAME # Initialize the test database. - cursor = db.cursor() + cursor = connection.cursor() self.output(1, "Initializing test database") management.init() @@ -145,7 +145,7 @@ class TestRunner: finally: # Rollback, in case of database errors. Otherwise they'd have # side effects on other tests. - db.rollback() + connection.rollback() if not self.which_tests: # Run the non-model tests in the other tests dir @@ -178,12 +178,12 @@ class TestRunner: # to do so, because it's not allowed to delete a database while being # connected to it. if settings.DATABASE_ENGINE != "sqlite3": - db.close() + connection.close() settings.DATABASE_NAME = old_database_name - cursor = db.cursor() + cursor = connection.cursor() self.output(1, "Deleting test database") try: - db.connection.autocommit(1) + connection.connection.autocommit(1) except AttributeError: pass else: