1818)
1919from django import VERSION as django_version
2020from django .db .models import Index , UniqueConstraint
21- from django .db .models .fields import AutoField , BigAutoField
21+ from django .db .models .fields import AutoField , BigAutoField , TextField
2222from django .db .models .sql .where import AND
2323from django .db .transaction import TransactionManagementError
2424from django .utils .encoding import force_str
@@ -34,6 +34,13 @@ def __hash__(self):
3434 def __eq__ (self , other ):
3535 return self .template == other .template and str (self .parts ['name' ]) == str (other .parts ['name' ])
3636
37+ def rename_column_references (self , table , old_column , new_column ):
38+ for part in self .parts .values ():
39+ if hasattr (part , 'rename_column_references' ):
40+ part .rename_column_references (table , old_column , new_column )
41+ condition = self .parts ['condition' ]
42+ if condition :
43+ self .parts ['condition' ] = condition .replace (f'[{ old_column } ]' , f'[{ new_column } ]' )
3744
3845class DatabaseSchemaEditor (BaseDatabaseSchemaEditor ):
3946
@@ -363,7 +370,30 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
363370 self .execute (self ._delete_constraint_sql (self .sql_delete_check , model , constraint_name ))
364371 # Have they renamed the column?
365372 if old_field .column != new_field .column :
373+ sql_restore_index = ''
374+ # Drop unique indexes for table to be altered
375+ index_names = self ._db_table_constraint_names (model ._meta .db_table , index = True )
376+ for index_name in index_names :
377+ if (index_name .endswith ('uniq' )):
378+ with self .connection .cursor () as cursor :
379+ cursor .execute (f"""
380+ SELECT COL_NAME(ic.object_id,ic.column_id) AS column_name,
381+ filter_definition
382+ FROM sys.indexes AS i
383+ INNER JOIN sys.index_columns AS ic
384+ ON i.object_id = ic.object_id AND i.index_id = ic.index_id
385+ WHERE i.object_id = OBJECT_ID('{ model ._meta .db_table } ')
386+ and i.name = '{ index_name } '
387+ """ )
388+ result = cursor .fetchall ()
389+ columns_to_recreate_index = ', ' .join (['%s' % self .quote_name (column [0 ]) for column in result ])
390+ filter_definition = result [0 ][1 ]
391+ sql_restore_index += f'CREATE UNIQUE INDEX { index_name } ON { model ._meta .db_table } ({ columns_to_recreate_index } ) WHERE { filter_definition } ;'
392+ self .execute (self ._db_table_delete_constraint_sql (self .sql_delete_index , model ._meta .db_table , index_name ))
366393 self .execute (self ._rename_field_sql (model ._meta .db_table , old_field , new_field , new_type ))
394+ # Restore indexes for altered table
395+ if (sql_restore_index ):
396+ self .execute (sql_restore_index .replace (f'[{ old_field .column } ]' , f'[{ new_field .column } ]' ))
367397 # Rename all references to the renamed column.
368398 for sql in self .deferred_sql :
369399 if isinstance (sql , DjStatement ):
@@ -410,6 +440,8 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
410440 self ._delete_unique_constraints (model , old_field , new_field , strict )
411441 # Drop indexes, SQL Server requires explicit deletion
412442 self ._delete_indexes (model , old_field , new_field )
443+ if not isinstance (new_field , TextField ):
444+ post_actions .append ((self ._create_index_sql (model , [new_field ]), ()))
413445 # Only if we have a default and there is a change from NULL to NOT NULL
414446 four_way_default_alteration = (
415447 new_field .has_default () and
@@ -557,6 +589,10 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
557589 fragment , other_actions = self ._alter_column_type_sql (
558590 new_rel .related_model , old_rel .field , new_rel .field , rel_type
559591 )
592+ # Drop related_model indexes, so it can be altered
593+ index_names = self ._db_table_constraint_names (old_rel .related_model ._meta .db_table , index = True )
594+ for index_name in index_names :
595+ self .execute (self ._db_table_delete_constraint_sql (self .sql_delete_index , old_rel .related_model ._meta .db_table , index_name ))
560596 self .execute (
561597 self .sql_alter_column % {
562598 "table" : self .quote_name (new_rel .related_model ._meta .db_table ),
@@ -566,6 +602,8 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
566602 )
567603 for sql , params in other_actions :
568604 self .execute (sql , params )
605+ # Restore related_model indexes
606+ self .execute (self ._create_index_sql (new_rel .related_model , [new_rel .field ]))
569607 # Does it have a foreign key?
570608 if (new_field .remote_field and
571609 (fks_dropped or not old_field .remote_field or not old_field .db_constraint ) and
@@ -608,6 +646,8 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
608646
609647 def _delete_indexes (self , model , old_field , new_field ):
610648 index_columns = []
649+ if old_field .null != new_field .null :
650+ index_columns .append ([old_field .column ])
611651 if old_field .db_index and new_field .db_index :
612652 index_columns .append ([old_field .column ])
613653 for fields in model ._meta .index_together :
0 commit comments