@@ -131,21 +131,9 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
131131 actions .append (fragment )
132132 post_actions .extend (other_actions )
133133 # Drop unique constraint, SQL Server requires explicit deletion
134- if old_field .unique and new_field .unique :
135- constraint_names = self ._constraint_names (model , [old_field .column ], unique = True )
136- if strict and len (constraint_names ) != 1 :
137- raise ValueError ("Found wrong number (%s) of unique constraints for %s.%s" % (
138- len (constraint_names ),
139- model ._meta .db_table ,
140- old_field .column ,
141- ))
142- for constraint_name in constraint_names :
143- self .execute (self ._delete_constraint_sql (self .sql_delete_unique , model , constraint_name ))
134+ self ._delete_unique_constraints (model , old_field , new_field , strict )
144135 # Drop indexes, SQL Server requires explicit deletion
145- elif old_field .db_index and new_field .db_index :
146- index_names = self ._constraint_names (model , [old_field .column ], index = True )
147- for index_name in index_names :
148- self .execute (self ._delete_constraint_sql (self .sql_delete_index , model , index_name ))
136+ self ._delete_indexes (model , old_field , new_field )
149137 # When changing a column NULL constraint to NOT NULL with a given
150138 # default value, we need to perform 4 steps:
151139 # 1. Add a default for new incoming writes
@@ -205,21 +193,9 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
205193 [],
206194 ))
207195 # Drop unique constraint, SQL Server requires explicit deletion
208- if old_field .unique and new_field .unique :
209- constraint_names = self ._constraint_names (model , [old_field .column ], unique = True )
210- if strict and len (constraint_names ) != 1 :
211- raise ValueError ("Found wrong number (%s) of unique constraints for %s.%s" % (
212- len (constraint_names ),
213- model ._meta .db_table ,
214- old_field .column ,
215- ))
216- for constraint_name in constraint_names :
217- self .execute (self ._delete_constraint_sql (self .sql_delete_unique , model , constraint_name ))
196+ self ._delete_unique_constraints (model , old_field , new_field , strict )
218197 # Drop indexes, SQL Server requires explicit deletion
219- elif old_field .db_index and new_field .db_index :
220- index_names = self ._constraint_names (model , [old_field .column ], index = True )
221- for index_name in index_names :
222- self .execute (self ._delete_constraint_sql (self .sql_delete_index , model , index_name ))
198+ self ._delete_indexes (model , old_field , new_field )
223199 # Only if we have a default and there is a change from NULL to NOT NULL
224200 four_way_default_alteration = (
225201 new_field .has_default () and
@@ -276,10 +252,28 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
276252 self .execute (self ._create_index_sql (model , [new_field ], suffix = "_uniq" ))
277253 # Restore an index, SQL Server requires explicit restoration
278254 if old_type != new_type or (old_field .null and not new_field .null ):
255+ unique_columns = []
279256 if old_field .unique and new_field .unique :
280- self .execute (self ._create_unique_sql (model , [new_field .column ]))
281- elif old_field .db_index and new_field .db_index :
282- self .execute (self ._create_index_sql (model , [new_field ]))
257+ unique_columns .append ([old_field .column ])
258+ else :
259+ for fields in model ._meta .unique_together :
260+ columns = [model ._meta .get_field (field ).column for field in fields ]
261+ if old_field .column in columns :
262+ unique_columns .append (columns )
263+ if unique_columns :
264+ for columns in unique_columns :
265+ self .execute (self ._create_unique_sql (model , columns ))
266+ index_columns = []
267+ if old_field .db_index and new_field .db_index :
268+ index_columns .append ([old_field ])
269+ else :
270+ for fields in model ._meta .index_together :
271+ columns = [model ._meta .get_field (field ) for field in fields ]
272+ if old_field .column in [c .column for c in columns ]:
273+ index_columns .append (columns )
274+ if index_columns :
275+ for columns in index_columns :
276+ self .execute (self ._create_index_sql (model , columns , suffix = '_idx' ))
283277 # Type alteration on primary key? Then we need to alter the column
284278 # referring to us.
285279 rels_to_update = []
@@ -369,6 +363,42 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
369363 if self .connection .features .connection_persists_old_columns :
370364 self .connection .close ()
371365
366+ def _delete_indexes (self , model , old_field , new_field ):
367+ index_columns = []
368+ if old_field .db_index and new_field .db_index :
369+ index_columns .append ([old_field .column ])
370+ else :
371+ for fields in model ._meta .index_together :
372+ columns = [model ._meta .get_field (field ).column for field in fields ]
373+ if old_field .column in columns :
374+ index_columns .append (columns )
375+ if index_columns :
376+ for columns in index_columns :
377+ index_names = self ._constraint_names (model , columns , index = True )
378+ for index_name in index_names :
379+ self .execute (self ._delete_constraint_sql (self .sql_delete_index , model , index_name ))
380+
381+ def _delete_unique_constraints (self , model , old_field , new_field , strict = False ):
382+ unique_columns = []
383+ if old_field .unique and new_field .unique :
384+ unique_columns .append ([old_field .column ])
385+ else :
386+ for fields in model ._meta .unique_together :
387+ columns = [model ._meta .get_field (field ).column for field in fields ]
388+ if old_field .column in columns :
389+ unique_columns .append (columns )
390+ if unique_columns :
391+ for columns in unique_columns :
392+ constraint_names = self ._constraint_names (model , columns , unique = True )
393+ if strict and len (constraint_names ) != 1 :
394+ raise ValueError ("Found wrong number (%s) of unique constraints for %s.%s" % (
395+ len (constraint_names ),
396+ model ._meta .db_table ,
397+ old_field .column ,
398+ ))
399+ for constraint_name in constraint_names :
400+ self .execute (self ._delete_constraint_sql (self .sql_delete_unique , model , constraint_name ))
401+
372402 def _rename_field_sql (self , table , old_field , new_field , new_type ):
373403 new_type = self ._set_field_new_type_null_status (old_field , new_type )
374404 return super (DatabaseSchemaEditor , self )._rename_field_sql (table , old_field , new_field , new_type )
@@ -600,47 +630,40 @@ def remove_field(self, model, field):
600630 # It might not actually have a column behind it
601631 if field .db_parameters (connection = self .connection )['type' ] is None :
602632 return
603- # Drop any FK constraints, MySQL requires explicit deletion
604- if field .remote_field :
605- fk_names = self ._constraint_names (model , [field .column ], foreign_key = True )
606- for fk_name in fk_names :
607- self .execute (self ._delete_constraint_sql (self .sql_delete_fk , model , fk_name ))
633+ # Drop any FK constraints, SQL Server requires explicit deletion
634+ with self .connection .cursor () as cursor :
635+ constraints = self .connection .introspection .get_constraints (cursor , model ._meta .db_table )
636+ for name , infodict in constraints .items ():
637+ if field .column in infodict ['columns' ] and infodict ['foreign_key' ]:
638+ self .execute (self ._delete_constraint_sql (self .sql_delete_fk , model , name ))
608639 # Drop any indexes, SQL Server requires explicit deletion
609- index_names = self ._constraint_names (model , [field .column ], index = True )
610- for index_name in index_names :
611- self .execute (
612- self .sql_delete_index % {
640+ for name , infodict in constraints .items ():
641+ if field .column in infodict ['columns' ] and infodict ['index' ]:
642+ self .execute (self .sql_delete_index % {
613643 "table" : self .quote_name (model ._meta .db_table ),
614- "name" : self .quote_name (index_name ),
615- }
616- )
644+ "name" : self .quote_name (name ),
645+ })
617646 # Drop primary key constraint, SQL Server requires explicit deletion
618- pk_names = self ._constraint_names (model , [field .column ], primary_key = True )
619- for pk_name in pk_names :
620- self .execute (
621- self .sql_delete_pk % {
647+ for name , infodict in constraints .items ():
648+ if field .column in infodict ['columns' ] and infodict ['primary_key' ]:
649+ self .execute (self .sql_delete_pk % {
622650 "table" : self .quote_name (model ._meta .db_table ),
623- "name" : self .quote_name (pk_name ),
624- }
625- )
651+ "name" : self .quote_name (name ),
652+ })
626653 # Drop check constraints, SQL Server requires explicit deletion
627- check_names = self ._constraint_names (model , [field .column ], check = True )
628- for check_name in check_names :
629- self .execute (
630- self .sql_delete_check % {
654+ for name , infodict in constraints .items ():
655+ if field .column in infodict ['columns' ] and infodict ['check' ]:
656+ self .execute (self .sql_delete_check % {
631657 "table" : self .quote_name (model ._meta .db_table ),
632- "name" : self .quote_name (check_name ),
633- }
634- )
658+ "name" : self .quote_name (name ),
659+ })
635660 # Drop unique constraints, SQL Server requires explicit deletion
636- unique_names = self ._constraint_names (model , [field .column ], unique = True )
637- for unique_name in unique_names :
638- self .execute (
639- self .sql_delete_unique % {
661+ for name , infodict in constraints .items ():
662+ if field .column in infodict ['columns' ] and infodict ['unique' ] and not infodict ['primary_key' ]:
663+ self .execute (self .sql_delete_unique % {
640664 "table" : self .quote_name (model ._meta .db_table ),
641- "name" : self .quote_name (unique_name ),
642- }
643- )
665+ "name" : self .quote_name (name ),
666+ })
644667 # Delete the column
645668 sql = self .sql_delete_column % {
646669 "table" : self .quote_name (model ._meta .db_table ),
0 commit comments