Django

Code

Ticket #2043: simple_evolution_support.diff

File simple_evolution_support.diff, 7.5 kB (added by ilias lazaridis <ilias@lazaridis.com>, 3 years ago)
  • P:/org/django/django/core/management.py

    old new  
    128128get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given app name(s)." 
    129129get_sql_create.args = APP_ARGS 
    130130 
     131#------------------------------------------------------------------------------ 
     132 
     133def table_field_exists(klass, f): 
     134    """ 
     135    Checks if a field is available within a table 
     136     
     137    Limited implementation, verifies only field-name 
     138 
     139    Status: draft 
     140    """     
     141    from django.db import backend, connection 
     142 
     143    cursor = connection.cursor() 
     144    backend_column_name = f.column 
     145 
     146    cursor.execute('select * from %s where 1 = 0' % klass._meta.db_table ) 
     147     
     148    exist = False 
     149    for col in cursor.description: 
     150        if backend_column_name == col[0]: 
     151            exist = True 
     152            break 
     153             
     154    return exist         
     155 
     156#------------------------------------------------------------------------------ 
     157def _get_sql_table_evolve(klass): 
     158    """ 
     159    Get the SQL required to evolve a single model. 
     160 
     161    Uses ALTER TABLE 
     162     
     163    Status: draft, sqlite3 specific. 
     164    """ 
     165    from django.db import backend 
     166        
     167    final_output = [] 
     168    str = '' 
     169    for f in klass._meta.fields:                     
     170        if not table_field_exists(klass, f): 
     171            statement, ref = _get_sql_field_def(klass, f) 
     172            field_def = ' '.join(statement) 
     173                    
     174            full_statement = [style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD COLUMN %s;' % \ 
     175                ( style.SQL_TABLE(backend.quote_name( klass._meta.db_table )), field_def) ] 
     176            final_output.append('\n'.join(full_statement)) 
     177 
     178    if final_output: 
     179        full_statement = [style.SQL_KEYWORD('VACUUM') + ';'] 
     180        final_output.append('\n'.join(full_statement))           
     181                       
     182    return final_output 
     183 
     184#------------------------------------------------------------------------------ 
     185 
     186def table_evolve(klass): 
     187    """ 
     188    evolves the underlying table for a single model 
     189     
     190    Status: draft 
     191    """ 
     192    from django.db import backend, connection, transaction 
     193 
     194    print "Checking table  %s model" % klass.__name__ 
     195 
     196    cursor = connection.cursor() 
     197    statements = _get_sql_table_evolve(klass) 
     198     
     199    if statements: 
     200        print "Evolving table for Class %s" % klass.__name__ 
     201        for statement in statements: 
     202            cursor.execute(statement) 
     203 
     204        transaction.commit_unless_managed() 
     205         
     206#------------------------------------------------------------------------------ 
     207         
     208def _get_sql_field_def(klass, f, models_already_seen=set() ): 
     209    """ 
     210    Get the SQL for a field definition 
     211    """ 
     212     
     213    # copied from _get_sql_model_create 
     214    # not neede lines are outcommented (will be removed after review) 
     215 
     216    from django.db import backend, get_creation_module, models 
     217    data_types = get_creation_module().DATA_TYPES 
     218 
     219    #opts = klass._meta 
     220    #final_output = [] 
     221    #table_output = [] 
     222    #pending_references = {} 
     223 
     224    if isinstance(f, models.ForeignKey): 
     225        rel_field = f.rel.get_related_field() 
     226        data_type = get_rel_data_type(rel_field) 
     227    else: 
     228        rel_field = f 
     229        data_type = f.get_internal_type() 
     230    col_type = data_types[data_type] 
     231    if col_type is not None: 
     232        # Make the definition (e.g. 'foo VARCHAR(30)') for this field. 
     233        field_output = [style.SQL_FIELD(backend.quote_name(f.column)), 
     234            style.SQL_COLTYPE(col_type % rel_field.__dict__)] 
     235        field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or ''))) 
     236        if f.unique: 
     237            field_output.append(style.SQL_KEYWORD('UNIQUE')) 
     238        if f.primary_key: 
     239            field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 
     240        if f.rel: 
     241            if f.rel.to in models_already_seen: 
     242                field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \ 
     243                    style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \ 
     244                    style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' 
     245                ) 
     246            #else: 
     247                # We haven't yet created the table to which this field 
     248                # is related, so save it for later. 
     249                #pr = pending_references.setdefault(f.rel.to, []).append((klass, f)) 
     250        #table_output.append(' '.join(field_output)) 
     251         
     252        # code added during refactoring 
     253        has_pending_ref = False 
     254        if f.rel: 
     255            if f.rel.to not in models_already_seen: 
     256                has_pending_ref = True 
     257                     
     258         
     259    return field_output, has_pending_ref 
     260 
     261#------------------------------------------------------------------------------ 
     262 
    131263def _get_sql_model_create(klass, models_already_seen=set()): 
    132264    """ 
    133265    Get the SQL required to create a single model. 
     
    141273    final_output = [] 
    142274    table_output = [] 
    143275    pending_references = {} 
    144     for f in opts.fields: 
    145         if isinstance(f, models.ForeignKey): 
    146             rel_field = f.rel.get_related_field() 
    147             data_type = get_rel_data_type(rel_field) 
    148         else: 
    149             rel_field = f 
    150             data_type = f.get_internal_type() 
    151         col_type = data_types[data_type] 
    152         if col_type is not None: 
    153             # Make the definition (e.g. 'foo VARCHAR(30)') for this field. 
    154             field_output = [style.SQL_FIELD(backend.quote_name(f.column)), 
    155                 style.SQL_COLTYPE(col_type % rel_field.__dict__)] 
    156             field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or ''))) 
    157             if f.unique: 
    158                 field_output.append(style.SQL_KEYWORD('UNIQUE')) 
    159             if f.primary_key: 
    160                 field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 
    161             if f.rel: 
    162                 if f.rel.to in models_already_seen: 
    163                     field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \ 
    164                         style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \ 
    165                         style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' 
    166                     ) 
    167                 else: 
    168                     # We haven't yet created the table to which this field 
    169                     # is related, so save it for later. 
    170                     pr = pending_references.setdefault(f.rel.to, []).append((klass, f)) 
    171             table_output.append(' '.join(field_output)) 
     276     
     277    for f in opts.fields:        
     278        field_output, has_pending_ref = _get_sql_field_def(klass, f, models_already_seen) 
     279        table_output.append(' '.join(field_output)) 
     280         
     281        if has_pending_ref: 
     282            pr = pending_references.setdefault(f.rel.to, []).append((klass, f)) 
     283                     
    172284    if opts.order_with_respect_to: 
    173285        table_output.append(style.SQL_FIELD(backend.quote_name('_order')) + ' ' + \ 
    174286            style.SQL_COLTYPE(data_types['IntegerField']) + ' ' + \ 
     
    455567        for model in model_list: 
    456568            # Create the model's database table, if it doesn't already exist. 
    457569            if model._meta.db_table in table_list: 
     570                table_evolve(model)                 
    458571                continue 
    459572            sql, references = _get_sql_model_create(model, seen_models) 
    460573            seen_models.add(model)