Django

Code

Changeset 5735

Show
Ignore:
Timestamp:
07/20/07 15:58:33 (1 year ago)
Author:
danderson
Message:

schema-evolution: re-applied schema evolution changes from:
http://kered.org/blog/wp-content/uploads/2007/07/django_schema_evolution-svn20070719patch.txt

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/schema-evolution/django/core/management.py

    r5734 r5735  
    482482    return output 
    483483 
     484def 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 
     550get_sql_evolution.help_doc = "Returns SQL to update an existing schema to match the existing models." 
     551get_sql_evolution.args = APP_ARGS 
     552 
     553def 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 
     586def 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     
     600def 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     
     632def 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 
     682def 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 
    484706def get_sql_all(app): 
    485707    "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module." 
     
    541763            if verbosity >= 2: 
    542764                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
    544766                continue 
    545767            sql, references = _get_sql_model_create(model, seen_models) 
     
    568790                    for statement in sql: 
    569791                        cursor.execute(statement) 
     792 
     793        for sql in get_sql_evolution(app): 
     794            print sql 
     795#            cursor.execute(sql) 
    570796 
    571797    transaction.commit_unless_managed() 
     
    15221748    'sqlreset': get_sql_reset, 
    15231749    'sqlsequencereset': get_sql_sequence_reset, 
     1750    'sqlevolve': get_sql_evolution, 
    15241751    'startapp': startapp, 
    15251752    'startproject': startproject, 
  • django/branches/schema-evolution/django/db/backends/mysql/base.py

    r5734 r5735  
    243243    return [] 
    244244 
     245def 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 
     255def 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 
     265def 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 
     281def 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     
    245287OPERATOR_MAPPING = { 
    246288    'exact': '= %s', 
  • django/branches/schema-evolution/django/db/backends/mysql/introspection.py

    r5734 r5735  
    7474    return indexes 
    7575 
     76def 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     
     83def 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     
    76113DATA_TYPES_REVERSE = { 
    77114    FIELD_TYPE.BLOB: 'TextField', 
  • django/branches/schema-evolution/django/db/backends/postgresql/base.py

    r5734 r5735  
    283283    return smart_unicode(s) 
    284284 
     285def 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 
     294def 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 
     307def 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     
     316def 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 
    285321# Register these custom typecasts, because Django expects dates/times to be 
    286322# in Python's native (standard-library) datetime/time format, whereas psycopg 
  • django/branches/schema-evolution/django/db/backends/postgresql/introspection.py

    r5734 r5735  
    6767    return indexes 
    6868 
     69def 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     
     76def 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 
    69121# Maps type codes to Django Field types. 
    70122DATA_TYPES_REVERSE = { 
  • django/branches/schema-evolution/django/db/backends/sqlite3/base.py

    r5734 r5735  
    214214    except: 
    215215        return False 
     216 
     217def 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 
     231def 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     
     238def 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 
     254def 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     
    216261 
    217262# SQLite requires LIKE statements to include an ESCAPE clause if the value 
  • django/branches/schema-evolution/django/db/backends/sqlite3/introspection.py

    r5734 r5735  
    4444    return indexes 
    4545 
     46def 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         
     53def 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     
    4683def _table_info(cursor, name): 
    4784    cursor.execute('PRAGMA table_info(%s)' % quote_name(name)) 
  • django/branches/schema-evolution/django/db/models/fields/__init__.py

    r5734 r5735  
    7777        prepopulate_from=None, unique_for_date=None, unique_for_month=None, 
    7878        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): 
    8080        self.name = name 
    8181        self.verbose_name = verbose_name 
     
    9898        self.help_text = help_text 
    9999        self.db_column = db_column 
     100        self.aka = aka 
    100101        self.db_tablespace = db_tablespace 
    101102 
  • django/branches/schema-evolution/django/db/models/options.py

    r5734 r5735  
    1616DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering', 
    1717                 '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') 
    1919 
    2020class Options(object): 
     
    2424        self.verbose_name_plural = None 
    2525        self.db_table = '' 
     26        self.aka = '' 
    2627        self.ordering = [] 
    2728        self.unique_together =  [] 
     
    7677            auto.creation_counter = -1 
    7778            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) 
    7887 
    7988        # If the db_table wasn't provided, use the app_label + module_name.