|
18 | 18 | from django.db.transaction import TransactionManagementError |
19 | 19 | from django.utils.encoding import force_str |
20 | 20 |
|
| 21 | +from collections import defaultdict |
| 22 | + |
21 | 23 |
|
22 | 24 | class Statement(DjStatement): |
23 | 25 | def __hash__(self): |
@@ -68,6 +70,8 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): |
68 | 70 | sql_create_unique_null = "CREATE UNIQUE INDEX %(name)s ON %(table)s(%(columns)s) " \ |
69 | 71 | "WHERE %(columns)s IS NOT NULL" |
70 | 72 |
|
| 73 | + _deferred_unique_indexes = defaultdict(list) |
| 74 | + |
71 | 75 | def _alter_column_default_sql(self, model, old_field, new_field, drop=False): |
72 | 76 | """ |
73 | 77 | Hook to specialize column default alteration. |
@@ -236,6 +240,12 @@ def alter_db_table(self, model, old_db_table, new_db_table): |
236 | 240 |
|
237 | 241 | return super().alter_db_table(model, old_db_table, new_db_table) |
238 | 242 |
|
| 243 | + def _delete_deferred_unique_indexes_for_field(self, field_name): |
| 244 | + deferred_statements = self._deferred_unique_indexes.get(field_name, []) |
| 245 | + for stmt in deferred_statements: |
| 246 | + if stmt in self.deferred_sql: |
| 247 | + self.deferred_sql.remove(stmt) |
| 248 | + |
239 | 249 | def _alter_field(self, model, old_field, new_field, old_type, new_type, |
240 | 250 | old_db_params, new_db_params, strict=False): |
241 | 251 | """Actually perform a "physical" (non-ManyToMany) field update.""" |
@@ -449,6 +459,7 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type, |
449 | 459 | ) |
450 | 460 | else: |
451 | 461 | self.execute(self._create_unique_sql(model, [new_field.column])) |
| 462 | + self._delete_deferred_unique_indexes_for_field(old_field) |
452 | 463 | # Added an index? |
453 | 464 | # constraint will no longer be used in lieu of an index. The following |
454 | 465 | # lines from the truth table show all True cases; the rest are False: |
@@ -477,6 +488,7 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type, |
477 | 488 | ) |
478 | 489 | else: |
479 | 490 | self.execute(self._create_unique_sql(model, columns=[old_field.column])) |
| 491 | + self._delete_deferred_unique_indexes_for_field(old_field) |
480 | 492 | else: |
481 | 493 | for fields in model._meta.unique_together: |
482 | 494 | columns = [model._meta.get_field(field).column for field in fields] |
@@ -644,9 +656,11 @@ def add_field(self, model, field): |
644 | 656 | not field.many_to_many and field.null and field.unique): |
645 | 657 |
|
646 | 658 | definition = definition.replace(' UNIQUE', '') |
647 | | - self.deferred_sql.append(self._create_index_sql( |
| 659 | + statement = self._create_index_sql( |
648 | 660 | model, [field], sql=self.sql_create_unique_null, suffix="_uniq" |
649 | | - )) |
| 661 | + ) |
| 662 | + self.deferred_sql.append(statement) |
| 663 | + self._deferred_unique_indexes[field].append(statement) |
650 | 664 |
|
651 | 665 | # Check constraints can go on the column SQL here |
652 | 666 | db_params = field.db_parameters(connection=self.connection) |
@@ -750,9 +764,11 @@ def create_model(self, model): |
750 | 764 | not field.many_to_many and field.null and field.unique): |
751 | 765 |
|
752 | 766 | definition = definition.replace(' UNIQUE', '') |
753 | | - self.deferred_sql.append(self._create_index_sql( |
| 767 | + statement = self._create_index_sql( |
754 | 768 | model, [field], sql=self.sql_create_unique_null, suffix="_uniq" |
755 | | - )) |
| 769 | + ) |
| 770 | + self.deferred_sql.append(statement) |
| 771 | + self._deferred_unique_indexes[field].append(statement) |
756 | 772 |
|
757 | 773 | # Check constraints can go on the column SQL here |
758 | 774 | db_params = field.db_parameters(connection=self.connection) |
|
0 commit comments