Changeset 5735
- Timestamp:
- 07/20/07 15:58:33 (1 year ago)
- Files:
-
- django/branches/schema-evolution/django/core/management.py (modified) (4 diffs)
- django/branches/schema-evolution/django/db/backends/mysql/base.py (modified) (1 diff)
- django/branches/schema-evolution/django/db/backends/mysql/introspection.py (modified) (1 diff)
- django/branches/schema-evolution/django/db/backends/postgresql/base.py (modified) (1 diff)
- django/branches/schema-evolution/django/db/backends/postgresql/introspection.py (modified) (1 diff)
- django/branches/schema-evolution/django/db/backends/sqlite3/base.py (modified) (1 diff)
- django/branches/schema-evolution/django/db/backends/sqlite3/introspection.py (modified) (1 diff)
- django/branches/schema-evolution/django/db/models/fields/__init__.py (modified) (2 diffs)
- django/branches/schema-evolution/django/db/models/options.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/schema-evolution/django/core/management.py
r5734 r5735 482 482 return output 483 483 484 def get_sql_evolution(app): 485 "Returns SQL to update an existing schema to match the existing models." 486 from django.db import get_creation_module, models, backend, get_introspection_module, connection 487 data_types = get_creation_module().DATA_TYPES 488 489 if not data_types: 490 # This must be the "dummy" database backend, which means the user 491 # hasn't set DATABASE_ENGINE. 492 sys.stderr.write(style.ERROR("Error: Django doesn't know which syntax to use for your SQL statements,\n" + 493 "because you haven't specified the DATABASE_ENGINE setting.\n" + 494 "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n")) 495 sys.exit(1) 496 497 # First, try validating the models. 498 _check_for_validation_errors() 499 500 final_output = [] 501 502 # stolen and trimmed from syncdb so that we know which models are about 503 # to be created (so we don't check them for updates) 504 table_list = _get_table_list() 505 seen_models = _get_installed_models(table_list) 506 created_models = set() 507 pending_references = {} 508 509 model_list = models.get_models(app) 510 for model in model_list: 511 # Create the model's database table, if it doesn't already exist. 512 if model._meta.db_table in table_list or model._meta.aka in table_list or len(set(model._meta.aka) & set(table_list))>0: 513 continue 514 sql, references = _get_sql_model_create(model, seen_models) 515 seen_models.add(model) 516 created_models.add(model) 517 table_list.append(model._meta.db_table) 518 519 introspection = get_introspection_module() 520 # This should work even if a connecton isn't available 521 try: 522 cursor = connection.cursor() 523 except: 524 cursor = None 525 526 # get the existing models, minus the models we've just created 527 app_models = models.get_models(app) 528 for model in created_models: 529 if model in app_models: 530 app_models.remove(model) 531 532 for klass in app_models: 533 534 output, new_table_name = get_sql_evolution_check_for_changed_model_name(klass) 535 final_output.extend(output) 536 537 output = get_sql_evolution_check_for_changed_field_flags(klass, new_table_name) 538 final_output.extend(output) 539 540 output = get_sql_evolution_check_for_changed_field_name(klass, new_table_name) 541 final_output.extend(output) 542 543 output = get_sql_evolution_check_for_new_fields(klass, new_table_name) 544 final_output.extend(output) 545 546 output = get_sql_evolution_check_for_dead_fields(klass, new_table_name) 547 final_output.extend(output) 548 549 return final_output 550 get_sql_evolution.help_doc = "Returns SQL to update an existing schema to match the existing models." 551 get_sql_evolution.args = APP_ARGS 552 553 def get_sql_evolution_check_for_new_fields(klass, new_table_name): 554 "checks for model fields that are not in the existing data structure" 555 from django.db import backend, get_creation_module, models, get_introspection_module, connection 556 data_types = get_creation_module().DATA_TYPES 557 cursor = connection.cursor() 558 introspection = get_introspection_module() 559 opts = klass._meta 560 output = [] 561 db_table = klass._meta.db_table 562 if new_table_name: 563 db_table = new_table_name 564 for f in opts.fields: 565 existing_fields = introspection.get_columns(cursor,db_table) 566 if f.column not in existing_fields and f.aka not in existing_fields and len(set(f.aka) & set(existing_fields))==0: 567 rel_field = f 568 data_type = f.get_internal_type() 569 col_type = data_types[data_type] 570 if col_type is not None: 571 # field_output = [] 572 # field_output.append('ALTER TABLE') 573 # field_output.append(db_table) 574 # field_output.append('ADD COLUMN') 575 # field_output.append(backend.quote_name(f.column)) 576 # field_output.append(style.SQL_COLTYPE(col_type % rel_field.__dict__)) 577 # field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or ''))) 578 # if f.unique: 579 # field_output.append(style.SQL_KEYWORD('UNIQUE')) 580 # if f.primary_key: 581 # field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 582 # output.append(' '.join(field_output) + ';') 583 output.append( backend.get_add_column_sql( db_table, f.column, style.SQL_COLTYPE(col_type % rel_field.__dict__), f.null, f.unique, f.primary_key ) ) 584 return output 585 586 def get_sql_evolution_check_for_changed_model_name(klass): 587 from django.db import backend, get_creation_module, models, get_introspection_module, connection 588 cursor = connection.cursor() 589 introspection = get_introspection_module() 590 table_list = introspection.get_table_list(cursor) 591 if klass._meta.db_table in table_list: 592 return [], None 593 if klass._meta.aka in table_list: 594 return [ 'ALTER TABLE '+ backend.quote_name(klass._meta.aka) +' RENAME TO '+ backend.quote_name(klass._meta.db_table) + ';' ], klass._meta.aka 595 elif len(set(klass._meta.aka) & set(table_list))==1: 596 return [ 'ALTER TABLE '+ backend.quote_name(klass._meta.aka[0]) +' RENAME TO '+ backend.quote_name(klass._meta.db_table) + ';' ], klass._meta.aka[0] 597 else: 598 return [], None 599 600 def get_sql_evolution_check_for_changed_field_name(klass, new_table_name): 601 from django.db import backend, get_creation_module, models, get_introspection_module, connection 602 data_types = get_creation_module().DATA_TYPES 603 cursor = connection.cursor() 604 introspection = get_introspection_module() 605 opts = klass._meta 606 output = [] 607 db_table = klass._meta.db_table 608 if new_table_name: 609 db_table = new_table_name 610 for f in opts.fields: 611 existing_fields = introspection.get_columns(cursor,db_table) 612 if f.column not in existing_fields and (f.aka in existing_fields or len(set(f.aka) & set(existing_fields)))==1: 613 old_col = None 614 if isinstance( f.aka, str ): 615 old_col = f.aka 616 else: 617 old_col = f.aka[0] 618 rel_field = f 619 data_type = f.get_internal_type() 620 col_type = data_types[data_type] 621 if col_type is not None: 622 field_output = [] 623 col_def = style.SQL_COLTYPE(col_type % rel_field.__dict__) +' '+ style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')) 624 if f.unique: 625 col_def += style.SQL_KEYWORD(' UNIQUE') 626 if f.primary_key: 627 col_def += style.SQL_KEYWORD(' PRIMARY KEY') 628 field_output.append( backend.get_change_column_name_sql( klass._meta.db_table, introspection.get_indexes(cursor,db_table), backend.quote_name(old_col), backend.quote_name(f.column), col_def ) ) 629 output.append(' '.join(field_output)) 630 return output 631 632 def get_sql_evolution_check_for_changed_field_flags(klass, new_table_name): 633 from django.db import backend, get_creation_module, models, get_introspection_module, connection 634 from django.db.models.fields import CharField, SlugField 635 from django.db.models.fields.related import RelatedField, ForeignKey 636 data_types = get_creation_module().DATA_TYPES 637 cursor = connection.cursor() 638 introspection = get_introspection_module() 639 opts = klass._meta 640 output = [] 641 db_table = klass._meta.db_table 642 if new_table_name: 643 db_table = new_table_name 644 for f in opts.fields: 645 existing_fields = introspection.get_columns(cursor,db_table) 646 cf = None # current field, ie what it is before any renames 647 if f.column in existing_fields: 648 cf = f.column 649 elif f.aka in existing_fields: 650 cf = f.aka 651 elif len(set(f.aka) & set(existing_fields))==1: 652 cf = f.aka[0] 653 else: 654 continue # no idea what column you're talking about - should be handled by get_sql_evolution_check_for_new_fields()) 655 data_type = f.get_internal_type() 656 if data_types.has_key(data_type): 657 column_flags = introspection.get_known_column_flags(cursor, db_table, cf) 658 if column_flags['allow_null']!=f.null or \ 659 ( not f.primary_key and isinstance(f, CharField) and column_flags['maxlength']!=str(f.maxlength) ) or \ 660 ( not f.primary_key and isinstance(f, SlugField) and column_flags['maxlength']!=str(f.maxlength) ) or \ 661 column_flags['unique']!=f.unique or \ 662 column_flags['primary_key']!=f.primary_key: 663 #column_flags['foreign_key']!=f.foreign_key: 664 # print 665 # print db_table, f.column, column_flags 666 # print "column_flags['allow_null']!=f.null", column_flags['allow_null']!=f.null 667 # print "not f.primary_key and isinstance(f, CharField) and column_flags['maxlength']!=str(f.maxlength)", not f.primary_key and isinstance(f, CharField) and column_flags['maxlength']!=str(f.maxlength) 668 # print "not f.primary_key and isinstance(f, SlugField) and column_flags['maxlength']!=str(f.maxlength)", not f.primary_key and isinstance(f, SlugField) and column_flags['maxlength']!=str(f.maxlength) 669 # print "column_flags['unique']!=f.unique", column_flags['unique']!=f.unique 670 # print "column_flags['primary_key']!=f.primary_key", column_flags['primary_key']!=f.primary_key 671 col_type = data_types[data_type] 672 col_type_def = style.SQL_COLTYPE(col_type % f.__dict__) 673 # col_def = style.SQL_COLTYPE(col_type % f.__dict__) +' '+ style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')) 674 # if f.unique: 675 # col_def += ' '+ style.SQL_KEYWORD('UNIQUE') 676 # if f.primary_key: 677 # col_def += ' '+ style.SQL_KEYWORD('PRIMARY KEY') 678 output.append( backend.get_change_column_def_sql( db_table, cf, col_type_def, f.null, f.unique, f.primary_key ) ) 679 #print db_table, cf, f.maxlength, introspection.get_known_column_flags(cursor, db_table, cf) 680 return output 681 682 def get_sql_evolution_check_for_dead_fields(klass, new_table_name): 683 from django.db import backend, get_creation_module, models, get_introspection_module, connection 684 from django.db.models.fields import CharField, SlugField 685 from django.db.models.fields.related import RelatedField, ForeignKey 686 data_types = get_creation_module().DATA_TYPES 687 cursor = connection.cursor() 688 introspection = get_introspection_module() 689 opts = klass._meta 690 output = [] 691 db_table = klass._meta.db_table 692 if new_table_name: 693 db_table = new_table_name 694 suspect_fields = set(introspection.get_columns(cursor,db_table)) 695 for f in opts.fields: 696 suspect_fields.discard(f.column) 697 suspect_fields.discard(f.aka) 698 suspect_fields.difference_update(f.aka) 699 if len(suspect_fields)>0: 700 output.append( '-- warning: as the following may cause data loss, it/they must be run manually' ) 701 for suspect_field in suspect_fields: 702 output.append( backend.get_drop_column_sql( db_table, suspect_field ) ) 703 output.append( '-- end warning' ) 704 return output 705 484 706 def get_sql_all(app): 485 707 "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module." … … 541 763 if verbosity >= 2: 542 764 print "Processing %s.%s model" % (app_name, model._meta.object_name) 543 if table_name_converter(model._meta.db_table) in table_list :765 if table_name_converter(model._meta.db_table) in table_list or table_name_converter(model._meta.aka) in table_list or len(set(model._meta.aka) & set(table_list))>0: 544 766 continue 545 767 sql, references = _get_sql_model_create(model, seen_models) … … 568 790 for statement in sql: 569 791 cursor.execute(statement) 792 793 for sql in get_sql_evolution(app): 794 print sql 795 # cursor.execute(sql) 570 796 571 797 transaction.commit_unless_managed() … … 1522 1748 'sqlreset': get_sql_reset, 1523 1749 'sqlsequencereset': get_sql_sequence_reset, 1750 'sqlevolve': get_sql_evolution, 1524 1751 'startapp': startapp, 1525 1752 'startproject': startproject, django/branches/schema-evolution/django/db/backends/mysql/base.py
r5734 r5735 243 243 return [] 244 244 245 def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ): 246 # mysql doesn't support column renames (AFAIK), so we fake it 247 # TODO: only supports a single primary key so far 248 pk_name = None 249 for key in indexes.keys(): 250 if indexes[key]['primary_key']: pk_name = key 251 output = [] 252 output.append( 'ALTER TABLE '+ quote_name(table_name) +' CHANGE COLUMN '+ quote_name(old_col_name) +' '+ quote_name(new_col_name) +' '+ col_def + ';' ) 253 return '\n'.join(output) 254 255 def get_change_column_def_sql( table_name, col_name, col_type, null, unique, primary_key ): 256 output = [] 257 col_def = col_type +' '+ ('%sNULL' % (not null and 'NOT ' or '')) 258 if unique: 259 col_def += ' '+ 'UNIQUE' 260 if primary_key: 261 col_def += ' '+ 'PRIMARY KEY' 262 output.append( 'ALTER TABLE '+ quote_name(table_name) +' MODIFY COLUMN '+ quote_name(col_name) +' '+ col_def + ';' ) 263 return '\n'.join(output) 264 265 def get_add_column_sql( table_name, col_name, col_type, null, unique, primary_key ): 266 output = [] 267 field_output = [] 268 field_output.append('ALTER TABLE') 269 field_output.append(quote_name(table_name)) 270 field_output.append('ADD COLUMN') 271 field_output.append(quote_name(col_name)) 272 field_output.append(col_type) 273 field_output.append(('%sNULL' % (not null and 'NOT ' or ''))) 274 if unique: 275 field_output.append(('UNIQUE')) 276 if primary_key: 277 field_output.append(('PRIMARY KEY')) 278 output.append(' '.join(field_output) + ';') 279 return '\n'.join(output) 280 281 def get_drop_column_sql( table_name, col_name ): 282 output = [] 283 output.append( '-- ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(col_name) + ';' ) 284 return '\n'.join(output) 285 286 245 287 OPERATOR_MAPPING = { 246 288 'exact': '= %s', django/branches/schema-evolution/django/db/backends/mysql/introspection.py
r5734 r5735 74 74 return indexes 75 75 76 def get_columns(cursor, table_name): 77 try: 78 cursor.execute("describe %s" % quote_name(table_name)) 79 return [row[0] for row in cursor.fetchall()] 80 except: 81 return [] 82 83 def get_known_column_flags( cursor, table_name, column_name ): 84 cursor.execute("describe %s" % quote_name(table_name)) 85 dict = {} 86 for row in cursor.fetchall(): 87 if row[0] == column_name: 88 89 # maxlength check goes here 90 if row[1][0:7]=='varchar': 91 dict['maxlength'] = row[1][8:len(row[1])-1] 92 93 # default flag check goes here 94 if row[2]=='YES': dict['allow_null'] = True 95 else: dict['allow_null'] = False 96 97 # primary/foreign/unique key flag check goes here 98 if row[3]=='PRI': dict['primary_key'] = True 99 else: dict['primary_key'] = False 100 if row[3]=='FOR': dict['foreign_key'] = True 101 else: dict['foreign_key'] = False 102 if row[3]=='UNI': dict['unique'] = True 103 else: dict['unique'] = False 104 105 # default value check goes here 106 # if row[4]=='NULL': dict['default'] = None 107 # else: dict['default'] = row[4] 108 dict['default'] = row[4] 109 110 # print table_name, column_name, dict 111 return dict 112 76 113 DATA_TYPES_REVERSE = { 77 114 FIELD_TYPE.BLOB: 'TextField', django/branches/schema-evolution/django/db/backends/postgresql/base.py
r5734 r5735 283 283 return smart_unicode(s) 284 284 285 def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ): 286 # TODO: only supports a single primary key so far 287 pk_name = None 288 for key in indexes.keys(): 289 if indexes[key]['primary_key']: pk_name = key 290 output = [] 291 output.append( 'ALTER TABLE '+ quote_name(table_name) +' RENAME COLUMN '+ quote_name(old_col_name) +' TO '+ quote_name(new_col_name) +';' ) 292 return '\n'.join(output) 293 294 def get_change_column_def_sql( table_name, col_name, col_type, null, unique, primary_key ): 295 output = [] 296 output.append( 'ALTER TABLE '+ quote_name(table_name) +' ADD COLUMN '+ quote_name(col_name+'_tmp') +' '+ col_type + ';' ) 297 output.append( 'UPDATE '+ quote_name(table_name) +' SET '+ quote_name(col_name+'_tmp') +' = '+ quote_name(col_name) + ';' ) 298 output.append( 'ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(col_name) +';' ) 299 output.append( 'ALTER TABLE '+ quote_name(table_name) +' RENAME COLUMN '+ quote_name(col_name+'_tmp') +' TO '+ quote_name(col_name) + ';' ) 300 if not null: 301 output.append( 'ALTER TABLE '+ quote_name(table_name) +' ALTER COLUMN '+ quote_name(col_name) +' SET NOT NULL;' ) 302 if unique: 303 output.append( 'ALTER TABLE '+ quote_name(table_name) +' ADD CONSTRAINT '+ table_name +'_'+ col_name +'_unique_constraint UNIQUE('+ col_name +');' ) 304 305 return '\n'.join(output) 306 307 def get_add_column_sql( table_name, col_name, col_type, null, unique, primary_key ): 308 output = [] 309 output.append( 'ALTER TABLE '+ quote_name(table_name) +' ADD COLUMN '+ quote_name(col_name) +' '+ col_type + ';' ) 310 if not null: 311 output.append( 'ALTER TABLE '+ quote_name(table_name) +' ALTER COLUMN '+ quote_name(col_name) +' SET NOT NULL;' ) 312 if unique: 313 output.append( 'ALTER TABLE '+ quote_name(table_name) +' ADD CONSTRAINT '+ table_name +'_'+ col_name +'_unique_constraint UNIQUE('+ col_name +');' ) 314 return '\n'.join(output) 315 316 def get_drop_column_sql( table_name, col_name ): 317 output = [] 318 output.append( '-- ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(col_name) + ';' ) 319 return '\n'.join(output) 320 285 321 # Register these custom typecasts, because Django expects dates/times to be 286 322 # in Python's native (standard-library) datetime/time format, whereas psycopg django/branches/schema-evolution/django/db/backends/postgresql/introspection.py
r5734 r5735 67 67 return indexes 68 68 69 def get_columns(cursor, table_name): 70 try: 71 cursor.execute("SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), (SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), a.attnotnull, a.attnum, pg_catalog.col_description(a.attrelid, a.attnum) FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid from pg_catalog.pg_class c where c.relname ~ '^%s$') AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum" % table_name) 72 return [row[0] for row in cursor.fetchall()] 73 except: 74 return [] 75 76 def get_known_column_flags( cursor, table_name, column_name ): 77 # print "SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), (SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), a.attnotnull, a.attnum, pg_catalog.col_description(a.attrelid, a.attnum) FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid from pg_catalog.pg_class c where c.relname ~ '^%s$') AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum" % table_name 78 cursor.execute("SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), (SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), a.attnotnull, a.attnum, pg_catalog.col_description(a.attrelid, a.attnum) FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid from pg_catalog.pg_class c where c.relname ~ '^%s$') AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum" % table_name) 79 dict = {} 80 dict['primary_key'] = False 81 dict['foreign_key'] = False 82 dict['unique'] = False 83 dict['default'] = '' 84 85 # dict['allow_null'] = False 86 for row in cursor.fetchall(): 87 if row[0] == column_name: 88 89 # maxlength check goes here 90 if row[1][0:17]=='character varying': 91 dict['maxlength'] = row[1][18:len(row[1])-1] 92 93 # null flag check goes here 94 dict['allow_null'] = not row[3] 95 96 # pk, fk and unique checks go here 97 # 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 98 unique_conname = None 99 shared_unique_connames = set() 100 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 ) 101 for row in cursor.fetchall(): 102 if row[2] == column_name: 103 if row[1]=='p': dict['primary_key'] = True 104 if row[1]=='f': dict['foreign_key'] = True 105 if row[1]=='u': unique_conname = row[0] 106 else: 107 if row[1]=='u': shared_unique_connames.add( row[0] ) 108 if unique_conname and unique_conname not in shared_unique_connames: 109 dict['unique'] = True 110 111 # default value check goes here 112 cursor.execute("select pg_attribute.attname, adsrc from pg_attrdef, pg_attribute WHERE pg_attrdef.adrelid=pg_attribute.attrelid and pg_attribute.attnum=pg_attrdef.adnum and pg_attrdef.adrelid = (SELECT c.oid from pg_catalog.pg_class c where c.relname ~ '^%s$')" % table_name ) 113 for row in cursor.fetchall(): 114 if row[0] == column_name: 115 if row[1][0:7] == 'nextval': continue 116 dict['default'] = row[1][1:row[1].index("'",1)] 117 118 # print table_name, column_name, dict 119 return dict 120 69 121 # Maps type codes to Django Field types. 70 122 DATA_TYPES_REVERSE = { django/branches/schema-evolution/django/db/backends/sqlite3/base.py
r5734 r5735 214 214 except: 215 215 return False 216 217 def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ): 218 # sqlite doesn't support column renames, so we fake it 219 # TODO: only supports a single primary key so far 220 pk_name = None 221 for key in indexes.keys(): 222 if indexes[key]['primary_key']: pk_name = key 223 output = [] 224 output.append( 'ALTER TABLE '+ quote_name(table_name) +' ADD COLUMN '+ quote_name(new_col_name) +' '+ col_def + ';' ) 225 output.append( 'UPDATE '+ quote_name(table_name) +' SET '+ new_col_name +' = '+ old_col_name +' WHERE '+ pk_name +'=(select '+ pk_name +' from '+ table_name +');' ) 226 output.append( '-- FYI: sqlite does not support deleting columns, so '+ quote_name(old_col_name) +' remains as cruft' ) 227 # use the following when sqlite gets drop support 228 #output.append( 'ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(old_col_name) ) 229 return '\n'.join(output) 230 231 def get_change_column_def_sql( table_name, col_name, col_def ): 232 # sqlite doesn't support column modifications, so we fake it 233 output = [] 234 # TODO: fake via renaming the table, building a new one and deleting the old 235 output.append('-- sqlite does not support column modifications '+ quote_name(table_name) +'.'+ quote_name(col_name) +' to '+ col_def) 236 return '\n'.join(output) 237 238 def get_add_column_sql( table_name, col_name, col_type, null, unique, primary_key ): 239 output = [] 240 field_output = [] 241 field_output.append('ALTER TABLE') 242 field_output.append(quote_name(table_name)) 243 field_output.append('ADD COLUMN') 244 field_output.append(quote_name(col_name)) 245 field_output.append(col_type) 246 field_output.append(('%sNULL' % (not null and 'NOT ' or ''))) 247 if unique: 248 field_output.append(('UNIQUE')) 249 if primary_key: 250 field_output.append(('PRIMARY KEY')) 251 output.append(' '.join(field_output) + ';') 252 return '\n'.join(output) 253 254 def get_drop_column_sql( table_name, col_name ): 255 output = [] 256 output.append( '-- FYI: sqlite does not support deleting columns, so '+ quote_name(old_col_name) +' remains as cruft' ) 257 # use the following when sqlite gets drop support 258 # output.append( '-- ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(col_name) ) 259 return '\n'.join(output) 260 216 261 217 262 # SQLite requires LIKE statements to include an ESCAPE clause if the value django/branches/schema-evolution/django/db/backends/sqlite3/introspection.py
r5734 r5735 44 44 return indexes 45 45 46 def get_columns(cursor, table_name): 47 try: 48 cursor.execute("PRAGMA table_info(%s)" % quote_name(table_name)) 49 return [row[1] for row in cursor.fetchall()] 50 except: 51 return [] 52 53 def get_known_column_flags( cursor, table_name, column_name ): 54 cursor.execute("PRAGMA table_info(%s)" % quote_name(table_name)) 55 dict = {} 56 for row in cursor.fetchall(): 57 if row[1] == column_name: 58 59 # maxlength check goes here 60 if row[2][0:7]=='varchar': 61 dict['maxlength'] = row[2][8:len(row[2])-1] 62 63 # default flag check goes here 64 #if row[2]=='YES': dict['allow_null'] = True 65 #else: dict['allow_null'] = False 66 67 # primary/foreign/unique key flag check goes here 68 #if row[3]=='PRI': dict['primary_key'] = True 69 #else: dict['primary_key'] = False 70 #if row[3]=='FOR': dict['foreign_key'] = True 71 #else: dict['foreign_key'] = False 72 #if row[3]=='UNI': dict['unique'] = True 73 #else: dict['unique'] = False 74 75 # default value check goes here 76 # if row[4]=='NULL': dict['default'] = None 77 # else: dict['default'] = row[4] 78 #dict['default'] = row[4] 79 80 print table_name, column_name, dict 81 return dict 82 46 83 def _table_info(cursor, name): 47 84 cursor.execute('PRAGMA table_info(%s)' % quote_name(name)) django/branches/schema-evolution/django/db/models/fields/__init__.py
r5734 r5735 77 77 prepopulate_from=None, unique_for_date=None, unique_for_month=None, 78 78 unique_for_year=None, validator_list=None, choices=None, radio_admin=None, 79 help_text='', db_column=None, db_tablespace=None):79 help_text='', db_column=None, aka=None, db_tablespace=None): 80 80 self.name = name 81 81 self.verbose_name = verbose_name … … 98 98 self.help_text = help_text 99 99 self.db_column = db_column 100 self.aka = aka 100 101 self.db_tablespace = db_tablespace 101 102 django/branches/schema-evolution/django/db/models/options.py
r5734 r5735 16 16 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering', 17 17 'unique_together', 'permissions', 'get_latest_by', 18 'order_with_respect_to', 'app_label', ' db_tablespace')18 'order_with_respect_to', 'app_label', 'aka', 'db_tablespace') 19 19 20 20 class Options(object): … … 24 24 self.verbose_name_plural = None 25 25 self.db_table = '' 26 self.aka = '' 26 27 self.ordering = [] 27 28 self.unique_together = [] … … 76 77 auto.creation_counter = -1 77 78 model.add_to_class('id', auto) 79 80 if isinstance(self.aka, str): 81 self.aka = "%s_%s" % (self.app_label, self.aka.lower()) 82 if isinstance(self.aka, tuple): 83 real_aka = [] 84 for some_aka in self.aka: 85 real_aka.append( "%s_%s" % (self.app_label, some_aka.lower()) ) 86 self.aka = tuple(real_aka) 78 87 79 88 # If the db_table wasn't provided, use the app_label + module_name.
