diff options
author | Derek Anderson <public@kered.org> | 2007-08-01 17:51:59 +0000 |
---|---|---|
committer | Derek Anderson <public@kered.org> | 2007-08-01 17:51:59 +0000 |
commit | 0b4c2c7ab1b32d5fa1befd86207d8ead52d6e4f7 (patch) | |
tree | 69b36c684f4f35cca0effae13b7066bcb5ed7be1 | |
parent | 4629092d792a38ad493361490252b77576262f53 (diff) | |
download | django-0b4c2c7ab1b32d5fa1befd86207d8ead52d6e4f7.tar.gz |
schema-evolution:
fixed postgresql constraint lookup after a table rename bug
pulled table renames into the backends
added postgresql unit tests
git-svn-id: http://code.djangoproject.com/svn/django/branches/schema-evolution@5784 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r-- | django/core/management.py | 9 | ||||
-rw-r--r-- | django/db/backends/mysql/base.py | 3 | ||||
-rw-r--r-- | django/db/backends/postgresql/base.py | 5 | ||||
-rw-r--r-- | django/db/backends/postgresql/introspection.py | 3 | ||||
-rw-r--r-- | django/db/backends/sqlite3/base.py | 3 | ||||
-rw-r--r-- | tests/modeltests/schema_evolution/models.py | 54 |
6 files changed, 72 insertions, 5 deletions
diff --git a/django/core/management.py b/django/core/management.py index 376d59118d..64857d52e5 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -5,6 +5,7 @@ import django from django.core.exceptions import ImproperlyConfigured from optparse import OptionParser from django.utils import termcolors +from django.conf import settings import os, re, shutil, sys, textwrap try: @@ -591,9 +592,9 @@ def get_sql_evolution_check_for_changed_model_name(klass): if klass._meta.db_table in table_list: return [], None if klass._meta.aka in table_list: - return [ 'ALTER TABLE '+ backend.quote_name(klass._meta.aka) +' RENAME TO '+ backend.quote_name(klass._meta.db_table) + ';' ], klass._meta.aka + return [ backend.get_change_table_name_sql( klass._meta.db_table, klass._meta.aka) ], klass._meta.aka elif len(set(klass._meta.aka) & set(table_list))==1: - return [ 'ALTER TABLE '+ backend.quote_name(klass._meta.aka[0]) +' RENAME TO '+ backend.quote_name(klass._meta.db_table) + ';' ], klass._meta.aka[0] + return [ backend.get_change_table_name_sql( klass._meta.db_table, klass._meta.aka[0]) ], klass._meta.aka[0] else: return [], None @@ -643,6 +644,7 @@ def get_sql_evolution_check_for_changed_field_flags(klass, new_table_name): db_table = new_table_name for f in opts.fields: existing_fields = introspection.get_columns(cursor,db_table) +# print existing_fields cf = None # current field, ie what it is before any renames if f.column in existing_fields: cf = f.column @@ -655,10 +657,11 @@ def get_sql_evolution_check_for_changed_field_flags(klass, new_table_name): data_type = f.get_internal_type() if data_types.has_key(data_type): column_flags = introspection.get_known_column_flags(cursor, db_table, cf) +# print db_table, cf, column_flags if column_flags['allow_null']!=f.null or \ ( not f.primary_key and isinstance(f, CharField) and column_flags['maxlength']!=str(f.maxlength) ) or \ ( not f.primary_key and isinstance(f, SlugField) and column_flags['maxlength']!=str(f.maxlength) ) or \ - column_flags['unique']!=f.unique or \ + ( column_flags['unique']!=f.unique and ( settings.DATABASE_ENGINE!='postgresql' or not f.primary_key ) ) or \ column_flags['primary_key']!=f.primary_key: #column_flags['foreign_key']!=f.foreign_key: # print diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index 7f5fa8d00e..6e9a5f0e46 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -242,6 +242,9 @@ def get_sql_sequence_reset(style, model_list): # No sequence reset required return [] +def get_change_table_name_sql( table_name, old_table_name ): + return 'ALTER TABLE '+ quote_name(old_table_name) +' RENAME TO '+ quote_name(table_name) + ';' + def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ): # mysql doesn't support column renames (AFAIK), so we fake it # TODO: only supports a single primary key so far diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index 3dd54726ea..0cf8967c7a 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -282,6 +282,11 @@ def typecast_string(s): return s return smart_unicode(s) +def get_change_table_name_sql( table_name, old_table_name ): + output = [] + output.append('ALTER TABLE '+ quote_name(old_table_name) +' RENAME TO '+ quote_name(table_name) + ';') + return '\n'.join(output) + def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ): # TODO: only supports a single primary key so far pk_name = None diff --git a/django/db/backends/postgresql/introspection.py b/django/db/backends/postgresql/introspection.py index 38d76c65f4..602239277a 100644 --- a/django/db/backends/postgresql/introspection.py +++ b/django/db/backends/postgresql/introspection.py @@ -97,8 +97,9 @@ def get_known_column_flags( cursor, table_name, column_name ): # print "select pg_constraint.conname, pg_constraint.contype, pg_attribute.attname from pg_constraint, pg_attribute where pg_constraint.conrelid=pg_attribute.attrelid and pg_attribute.attnum=any(pg_constraint.conkey) and pg_constraint.conname~'^%s'" % table_name unique_conname = None shared_unique_connames = set() - cursor.execute("select pg_constraint.conname, pg_constraint.contype, pg_attribute.attname from pg_constraint, pg_attribute where pg_constraint.conrelid=pg_attribute.attrelid and pg_attribute.attnum=any(pg_constraint.conkey) and pg_constraint.conname~'^%s'" % table_name ) + cursor.execute("select pg_constraint.conname, pg_constraint.contype, pg_attribute.attname from pg_constraint, pg_attribute, pg_class where pg_constraint.conrelid=pg_class.oid and pg_constraint.conrelid=pg_attribute.attrelid and pg_attribute.attnum=any(pg_constraint.conkey) and pg_class.relname='%s'" % table_name ) for row in cursor.fetchall(): +# print row if row[2] == column_name: if row[1]=='p': dict['primary_key'] = True if row[1]=='f': dict['foreign_key'] = True diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 0bae2de216..67c56daada 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -214,6 +214,9 @@ def _sqlite_regexp(re_pattern, re_string): except: return False +def get_change_table_name_sql( table_name, old_table_name ): + return 'ALTER TABLE '+ quote_name(old_table_name) +' RENAME TO '+ quote_name(table_name) + ';' + def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ): # sqlite doesn't support column renames, so we fake it # TODO: only supports a single primary key so far diff --git a/tests/modeltests/schema_evolution/models.py b/tests/modeltests/schema_evolution/models.py index 7842e6209a..b401881714 100644 --- a/tests/modeltests/schema_evolution/models.py +++ b/tests/modeltests/schema_evolution/models.py @@ -3,6 +3,7 @@ Schema Evolution Tests """ from django.db import models +from django.conf import settings GENDER_CHOICES = ( ('M', 'Male'), @@ -27,7 +28,10 @@ __test__ = {'API_TESTS':""" >>> from django.db import connection, get_introspection_module >>> app = models.get_apps()[-1] >>> cursor = connection.cursor() +"""} +if settings.DATABASE_ENGINE == 'mysql': + __test__['API_TESTS'] += """ # the table as it is supposed to be >>> create_table_sql = management.get_sql_all(app) >>> print create_table_sql @@ -85,7 +89,55 @@ ALTER TABLE `schema_evolution_person` DROP COLUMN `gender`; 0L >>> management.get_sql_evolution(app) ['ALTER TABLE `schema_evolution_person` MODIFY COLUMN `name` varchar(20) NOT NULL;'] +""" + +if settings.DATABASE_ENGINE == 'postgresql': + __test__['API_TESTS'] += """ +# the table as it is supposed to be +>>> create_table_sql = management.get_sql_all(app) +>>> print create_table_sql +['CREATE TABLE "schema_evolution_person" (\\n "id" serial NOT NULL PRIMARY KEY,\\n "name" varchar(20) NOT NULL,\\n "gender" varchar(1) NOT NULL,\\n "gender2" varchar(1) NOT NULL\\n)\\n;'] +# make sure we don't evolve an unedited table +>>> management.get_sql_evolution(app) +[] -"""} +# delete a column, so it looks like we've recently added a field +>>> cursor.execute( backend.get_drop_column_sql( 'schema_evolution_person', 'gender' ) ) +>>> management.get_sql_evolution(app) +['ALTER TABLE "schema_evolution_person" ADD COLUMN "gender" varchar(1);\\nALTER TABLE "schema_evolution_person" ALTER COLUMN "gender" SET NOT NULL;'] + +# reset the db +>>> cursor.execute('DROP TABLE schema_evolution_person;'); cursor.execute(create_table_sql[0]) + +# add a column, so it looks like we've recently deleted a field +>>> cursor.execute( backend.get_add_column_sql( 'schema_evolution_person', 'gender_nothere', 'varchar(1)', True, False, False ) ) +>>> management.get_sql_evolution(app) +['-- warning: as the following may cause data loss, it/they must be run manually', u'-- ALTER TABLE "schema_evolution_person" DROP COLUMN "gender_nothere";', '-- end warning'] + +# reset the db +>>> cursor.execute('DROP TABLE schema_evolution_person;'); cursor.execute(create_table_sql[0]) + +# rename column, so it looks like we've recently renamed a field +>>> cursor.execute( backend.get_change_column_name_sql( 'schema_evolution_person', {}, 'gender2', 'gender_old', 'varchar(1)' ) ) +>>> management.get_sql_evolution(app) +['ALTER TABLE "schema_evolution_person" RENAME COLUMN "gender_old" TO "gender2";'] + +# reset the db +>>> cursor.execute('DROP TABLE schema_evolution_person;'); cursor.execute(create_table_sql[0]) + +# rename table, so it looks like we've recently renamed a model +>>> cursor.execute( backend.get_change_table_name_sql( 'schema_evolution_personold', 'schema_evolution_person' ) ) +>>> management.get_sql_evolution(app) +['ALTER TABLE "schema_evolution_personold" RENAME TO "schema_evolution_person";'] + +# reset the db +>>> cursor.execute(create_table_sql[0]) + +# change column flags, so it looks like we've recently changed a column flag +>>> cursor.execute( backend.get_change_column_def_sql( 'schema_evolution_person', 'name', 'varchar(10)', True, False, False ) ) +>>> management.get_sql_evolution(app) +['ALTER TABLE "schema_evolution_person" ADD COLUMN "name_tmp" varchar(20);\\nUPDATE "schema_evolution_person" SET "name_tmp" = "name";\\nALTER TABLE "schema_evolution_person" DROP COLUMN "name";\\nALTER TABLE "schema_evolution_person" RENAME COLUMN "name_tmp" TO "name";\\nALTER TABLE "schema_evolution_person" ALTER COLUMN "name" SET NOT NULL;'] + +""" |