1818)
1919from django import VERSION as django_version
2020from django .db .models import Index , UniqueConstraint
21- from django .db .models .fields import AutoField , BigAutoField , TextField
21+ from django .db .models .fields import AutoField , BigAutoField
2222from django .db .models .sql .where import AND
2323from django .db .transaction import TransactionManagementError
2424from django .utils .encoding import force_str
2727 from django .db .models .sql import Query
2828 from django .db .backends .ddl_references import Expressions
2929
30+
3031class Statement (DjStatement ):
3132 def __hash__ (self ):
3233 return hash ((self .template , str (self .parts ['name' ])))
@@ -42,6 +43,7 @@ def rename_column_references(self, table, old_column, new_column):
4243 if condition :
4344 self .parts ['condition' ] = condition .replace (f'[{ old_column } ]' , f'[{ new_column } ]' )
4445
46+
4547class DatabaseSchemaEditor (BaseDatabaseSchemaEditor ):
4648
4749 _sql_check_constraint = " CONSTRAINT %(name)s CHECK (%(check)s)"
@@ -389,7 +391,8 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
389391 columns_to_recreate_index = ', ' .join (['%s' % self .quote_name (column [0 ]) for column in result ])
390392 filter_definition = result [0 ][1 ]
391393 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 ))
394+ self .execute (self ._db_table_delete_constraint_sql (
395+ self .sql_delete_index , model ._meta .db_table , index_name ))
393396 self .execute (self ._rename_field_sql (model ._meta .db_table , old_field , new_field , new_type ))
394397 # Restore indexes for altered table
395398 if (sql_restore_index ):
@@ -440,7 +443,7 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
440443 self ._delete_unique_constraints (model , old_field , new_field , strict )
441444 # Drop indexes, SQL Server requires explicit deletion
442445 self ._delete_indexes (model , old_field , new_field )
443- if not isinstance ( new_field , TextField ):
446+ if not new_field . get_internal_type () in ( "JSONField" , " TextField" ) and not ( old_field . db_index and new_field . db_index ):
444447 post_actions .append ((self ._create_index_sql (model , [new_field ]), ()))
445448 # Only if we have a default and there is a change from NULL to NOT NULL
446449 four_way_default_alteration = (
@@ -562,7 +565,10 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
562565 index_columns .append (columns )
563566 if index_columns :
564567 for columns in index_columns :
565- self .execute (self ._create_index_sql (model , columns , suffix = '_idx' ))
568+ create_index_sql_statement = self ._create_index_sql (model , columns )
569+ if create_index_sql_statement .__str__ () not in [sql .__str__ () for sql in self .deferred_sql ]:
570+ self .execute (create_index_sql_statement )
571+
566572 # Type alteration on primary key? Then we need to alter the column
567573 # referring to us.
568574 rels_to_update = []
@@ -592,7 +598,8 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
592598 # Drop related_model indexes, so it can be altered
593599 index_names = self ._db_table_constraint_names (old_rel .related_model ._meta .db_table , index = True )
594600 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 ))
601+ self .execute (self ._db_table_delete_constraint_sql (
602+ self .sql_delete_index , old_rel .related_model ._meta .db_table , index_name ))
596603 self .execute (
597604 self .sql_alter_column % {
598605 "table" : self .quote_name (new_rel .related_model ._meta .db_table ),
@@ -646,10 +653,10 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
646653
647654 def _delete_indexes (self , model , old_field , new_field ):
648655 index_columns = []
649- if old_field .null != new_field .null :
650- index_columns .append ([old_field .column ])
651656 if old_field .db_index and new_field .db_index :
652657 index_columns .append ([old_field .column ])
658+ elif old_field .null != new_field .null :
659+ index_columns .append ([old_field .column ])
653660 for fields in model ._meta .index_together :
654661 columns = [model ._meta .get_field (field ).column for field in fields ]
655662 if old_field .column in columns :
@@ -754,12 +761,13 @@ def add_field(self, model, field):
754761 self .connection .close ()
755762
756763 if django_version >= (4 , 0 ):
757- def _create_unique_sql (self , model , fields , name = None , condition = None , deferrable = None , include = None , opclasses = None , expressions = None ):
758- if (deferrable and not getattr (self .connection .features , 'supports_deferrable_unique_constraints' , False )
759- or
764+ def _create_unique_sql (self , model , fields ,
765+ name = None , condition = None , deferrable = None ,
766+ include = None , opclasses = None , expressions = None ):
767+ if (deferrable and not getattr (self .connection .features , 'supports_deferrable_unique_constraints' , False ) or
760768 (condition and not self .connection .features .supports_partial_indexes ) or
761769 (include and not self .connection .features .supports_covering_indexes ) or
762- (expressions and not self .connection .features .supports_expression_indexes )):
770+ (expressions and not self .connection .features .supports_expression_indexes )):
763771 return None
764772
765773 def create_unique_name (* args , ** kwargs ):
@@ -803,12 +811,13 @@ def create_unique_name(*args, **kwargs):
803811 include = include ,
804812 )
805813 else :
806- def _create_unique_sql (self , model , columns , name = None , condition = None , deferrable = None , include = None , opclasses = None , expressions = None ):
807- if (deferrable and not getattr (self .connection .features , 'supports_deferrable_unique_constraints' , False )
808- or
814+ def _create_unique_sql (self , model , columns ,
815+ name = None , condition = None , deferrable = None ,
816+ include = None , opclasses = None , expressions = None ):
817+ if (deferrable and not getattr (self .connection .features , 'supports_deferrable_unique_constraints' , False ) or
809818 (condition and not self .connection .features .supports_partial_indexes ) or
810819 (include and not self .connection .features .supports_covering_indexes ) or
811- (expressions and not self .connection .features .supports_expression_indexes )):
820+ (expressions and not self .connection .features .supports_expression_indexes )):
812821 return None
813822
814823 def create_unique_name (* args , ** kwargs ):
@@ -823,7 +832,7 @@ def create_unique_name(*args, **kwargs):
823832 statement_args = {
824833 "deferrable" : self ._deferrable_constraint_sql (deferrable )
825834 } if django_version >= (3 , 1 ) else {}
826- include = self ._index_include_sql (model , include ) if django_version >= (3 , 2 ) else ''
835+ include = self ._index_include_sql (model , include ) if django_version >= (3 , 2 ) else ''
827836
828837 if condition :
829838 return Statement (
@@ -973,7 +982,8 @@ def _delete_unique_sql(
973982 if condition or include or opclasses :
974983 sql = self .sql_delete_index
975984 with self .connection .cursor () as cursor :
976- cursor .execute ("SELECT 1 FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE CONSTRAINT_NAME = '%s'" % name )
985+ cursor .execute (
986+ "SELECT 1 FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE CONSTRAINT_NAME = '%s'" % name )
977987 row = cursor .fetchone ()
978988 if row :
979989 sql = self .sql_delete_unique
@@ -1113,6 +1123,6 @@ def _create_index_name(self, table_name, column_names, suffix=""):
11131123 index_name = super ()._create_index_name (table_name , column_names , suffix )
11141124 # Check if the db_table specified a user-defined schema
11151125 if ('].[' in index_name ):
1116- new_index_name = index_name .replace ('[' ,'' ).replace (']' ,'' ).replace ('.' , '_' )
1126+ new_index_name = index_name .replace ('[' , '' ).replace (']' , '' ).replace ('.' , '_' )
11171127 return new_index_name
11181128 return index_name
0 commit comments