mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Reverted "Fixed #28646 -- Prevented duplicate index when unique is set to True on PostgreSQL."
This reverts commit 9cf9c796be
due to a crash on Oracle
as it didn't allow multiple indexes on the same field.
This commit is contained in:
parent
8cf931dd2f
commit
3dac3271d2
@ -964,7 +964,9 @@ class BaseDatabaseSchemaEditor:
|
|||||||
fks_dropped.add((old_field.column,))
|
fks_dropped.add((old_field.column,))
|
||||||
self.execute(self._delete_fk_sql(model, fk_name))
|
self.execute(self._delete_fk_sql(model, fk_name))
|
||||||
# Has unique been removed?
|
# Has unique been removed?
|
||||||
if old_field.unique and not old_field.primary_key and not new_field.unique:
|
if old_field.unique and (
|
||||||
|
not new_field.unique or self._field_became_primary_key(old_field, new_field)
|
||||||
|
):
|
||||||
# Find the unique constraint for this field
|
# Find the unique constraint for this field
|
||||||
meta_constraint_names = {
|
meta_constraint_names = {
|
||||||
constraint.name for constraint in model._meta.constraints
|
constraint.name for constraint in model._meta.constraints
|
||||||
|
@ -140,13 +140,6 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
|||||||
return sequence["name"]
|
return sequence["name"]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _is_changing_type_of_indexed_text_column(self, old_field, old_type, new_type):
|
|
||||||
return (old_field.db_index or old_field.unique) and (
|
|
||||||
(old_type.startswith("varchar") and not new_type.startswith("varchar"))
|
|
||||||
or (old_type.startswith("text") and not new_type.startswith("text"))
|
|
||||||
or (old_type.startswith("citext") and not new_type.startswith("citext"))
|
|
||||||
)
|
|
||||||
|
|
||||||
def _alter_column_type_sql(
|
def _alter_column_type_sql(
|
||||||
self, model, old_field, new_field, new_type, old_collation, new_collation
|
self, model, old_field, new_field, new_type, old_collation, new_collation
|
||||||
):
|
):
|
||||||
@ -154,7 +147,11 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
|||||||
# different type.
|
# different type.
|
||||||
old_db_params = old_field.db_parameters(connection=self.connection)
|
old_db_params = old_field.db_parameters(connection=self.connection)
|
||||||
old_type = old_db_params["type"]
|
old_type = old_db_params["type"]
|
||||||
if self._is_changing_type_of_indexed_text_column(old_field, old_type, new_type):
|
if (old_field.db_index or old_field.unique) and (
|
||||||
|
(old_type.startswith("varchar") and not new_type.startswith("varchar"))
|
||||||
|
or (old_type.startswith("text") and not new_type.startswith("text"))
|
||||||
|
or (old_type.startswith("citext") and not new_type.startswith("citext"))
|
||||||
|
):
|
||||||
index_name = self._create_index_name(
|
index_name = self._create_index_name(
|
||||||
model._meta.db_table, [old_field.column], suffix="_like"
|
model._meta.db_table, [old_field.column], suffix="_like"
|
||||||
)
|
)
|
||||||
@ -258,25 +255,6 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
|||||||
model, old_field, new_field, new_type, old_collation, new_collation
|
model, old_field, new_field, new_type, old_collation, new_collation
|
||||||
)
|
)
|
||||||
|
|
||||||
def _new_index_should_be_added(self, old_field, new_field):
|
|
||||||
return not (old_field.db_index or old_field.unique) and (
|
|
||||||
new_field.db_index or new_field.unique
|
|
||||||
)
|
|
||||||
|
|
||||||
def _deleted_index_should_be_recreated(
|
|
||||||
self, old_field, new_field, old_type, new_type
|
|
||||||
):
|
|
||||||
if (
|
|
||||||
not old_field.unique
|
|
||||||
and (
|
|
||||||
not new_field.db_index
|
|
||||||
or (new_field.unique and not new_field.primary_key)
|
|
||||||
)
|
|
||||||
) or (
|
|
||||||
self._is_changing_type_of_indexed_text_column(old_field, old_type, new_type)
|
|
||||||
):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _alter_field(
|
def _alter_field(
|
||||||
self,
|
self,
|
||||||
model,
|
model,
|
||||||
@ -299,10 +277,8 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
|||||||
strict,
|
strict,
|
||||||
)
|
)
|
||||||
# Added an index? Create any PostgreSQL-specific indexes.
|
# Added an index? Create any PostgreSQL-specific indexes.
|
||||||
if self._new_index_should_be_added(
|
if (not (old_field.db_index or old_field.unique) and new_field.db_index) or (
|
||||||
old_field, new_field
|
not old_field.unique and new_field.unique
|
||||||
) or self._deleted_index_should_be_recreated(
|
|
||||||
old_field, new_field, old_type, new_type
|
|
||||||
):
|
):
|
||||||
like_index_statement = self._create_like_index_sql(model, new_field)
|
like_index_statement = self._create_like_index_sql(model, new_field)
|
||||||
if like_index_statement is not None:
|
if like_index_statement is not None:
|
||||||
|
@ -102,7 +102,7 @@ class MigrationTestBase(TransactionTestCase):
|
|||||||
.values()
|
.values()
|
||||||
if (
|
if (
|
||||||
c["columns"] == list(columns)
|
c["columns"] == list(columns)
|
||||||
and (index_type is None or c.get("type") == index_type)
|
and (index_type is None or c["type"] == index_type)
|
||||||
and not c["unique"]
|
and not c["unique"]
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import math
|
import math
|
||||||
import unittest
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
@ -6214,52 +6213,6 @@ class OperationTests(OperationTestBase):
|
|||||||
self.assertEqual(pony_new.static, 2)
|
self.assertEqual(pony_new.static, 2)
|
||||||
|
|
||||||
|
|
||||||
class PrimaryKeyOperations(OperationTestBase):
|
|
||||||
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific")
|
|
||||||
def test_slugfields_change_primary_key_operations(self):
|
|
||||||
operation1 = migrations.CreateModel(
|
|
||||||
"SimpleModel",
|
|
||||||
[
|
|
||||||
("field1", models.SlugField(max_length=20, primary_key=True)),
|
|
||||||
("field2", models.SlugField(max_length=20)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
operation2 = migrations.AlterField(
|
|
||||||
"SimpleModel",
|
|
||||||
"field1",
|
|
||||||
models.SlugField(max_length=20, primary_key=False),
|
|
||||||
)
|
|
||||||
operation3 = migrations.AlterField(
|
|
||||||
"SimpleModel",
|
|
||||||
"field2",
|
|
||||||
models.SlugField(max_length=20, primary_key=True),
|
|
||||||
)
|
|
||||||
project_state = ProjectState()
|
|
||||||
new_state = project_state.clone()
|
|
||||||
operation1.state_forwards("migrtest", new_state)
|
|
||||||
|
|
||||||
self.assertTableNotExists("migrtest_simplemodel")
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
operation1.state_forwards("migrtest", new_state)
|
|
||||||
operation1.database_forwards("migrtest", editor, project_state, new_state)
|
|
||||||
project_state, new_state = new_state, new_state.clone()
|
|
||||||
operation2.state_forwards("migrtest", new_state)
|
|
||||||
operation2.database_forwards("migrtest", editor, project_state, new_state)
|
|
||||||
project_state, new_state = new_state, new_state.clone()
|
|
||||||
operation3.state_forwards("migrtest", new_state)
|
|
||||||
operation3.database_forwards("migrtest", editor, project_state, new_state)
|
|
||||||
self.assertTableExists("migrtest_simplemodel")
|
|
||||||
self.assertColumnExists("migrtest_simplemodel", "field1")
|
|
||||||
self.assertColumnExists("migrtest_simplemodel", "field2")
|
|
||||||
with connection.cursor() as cursor:
|
|
||||||
primary_keys = connection.introspection.get_primary_key_columns(
|
|
||||||
cursor, "migrtest_simplemodel"
|
|
||||||
)
|
|
||||||
self.assertEqual(["field2"], primary_keys)
|
|
||||||
self.assertIndexExists("migrtest_simplemodel", ["field1"], index_type="idx")
|
|
||||||
self.assertIndexExists("migrtest_simplemodel", ["field2"], index_type="idx")
|
|
||||||
|
|
||||||
|
|
||||||
class SwappableOperationTests(OperationTestBase):
|
class SwappableOperationTests(OperationTestBase):
|
||||||
"""
|
"""
|
||||||
Key operations ignore swappable models
|
Key operations ignore swappable models
|
||||||
|
@ -147,20 +147,6 @@ class IntegerPK(models.Model):
|
|||||||
db_table = "INTEGERPK" # uppercase to ensure proper quoting
|
db_table = "INTEGERPK" # uppercase to ensure proper quoting
|
||||||
|
|
||||||
|
|
||||||
class CharFieldPK(models.Model):
|
|
||||||
field1 = models.CharField(max_length=10, primary_key=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
apps = new_apps
|
|
||||||
|
|
||||||
|
|
||||||
class CharFieldPKUnique(models.Model):
|
|
||||||
field1 = models.CharField(max_length=10, primary_key=True, unique=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
apps = new_apps
|
|
||||||
|
|
||||||
|
|
||||||
class Note(models.Model):
|
class Note(models.Model):
|
||||||
info = models.TextField()
|
info = models.TextField()
|
||||||
address = models.TextField(null=True)
|
address = models.TextField(null=True)
|
||||||
|
@ -86,8 +86,6 @@ from .models import (
|
|||||||
BookWithO2O,
|
BookWithO2O,
|
||||||
BookWithoutAuthor,
|
BookWithoutAuthor,
|
||||||
BookWithSlug,
|
BookWithSlug,
|
||||||
CharFieldPK,
|
|
||||||
CharFieldPKUnique,
|
|
||||||
IntegerPK,
|
IntegerPK,
|
||||||
Node,
|
Node,
|
||||||
Note,
|
Note,
|
||||||
@ -123,8 +121,6 @@ class SchemaTests(TransactionTestCase):
|
|||||||
BookWithLongName,
|
BookWithLongName,
|
||||||
BookWithO2O,
|
BookWithO2O,
|
||||||
BookWithSlug,
|
BookWithSlug,
|
||||||
CharFieldPK,
|
|
||||||
CharFieldPKUnique,
|
|
||||||
IntegerPK,
|
IntegerPK,
|
||||||
Node,
|
Node,
|
||||||
Note,
|
Note,
|
||||||
@ -5214,213 +5210,6 @@ class SchemaTests(TransactionTestCase):
|
|||||||
["schema_tag_slug_2c418ba3_like", "schema_tag_slug_key"],
|
["schema_tag_slug_2c418ba3_like", "schema_tag_slug_key"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific")
|
|
||||||
def test_charfield_primary_key_to_db_index(self):
|
|
||||||
# Create the table and verify initial indexes.
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.create_model(CharFieldPK)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(CharFieldPK, "field1"),
|
|
||||||
["schema_charfieldpk_field1_0eb93b91_like", "schema_charfieldpk_pkey"],
|
|
||||||
)
|
|
||||||
# Alter to remove primary_key and set db_index=True.
|
|
||||||
old_field1 = CharFieldPK._meta.get_field("field1")
|
|
||||||
new_field1 = CharField(db_index=True, primary_key=False)
|
|
||||||
new_field1.set_attributes_from_name("field1")
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(CharFieldPK, old_field1, new_field1, strict=True)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(CharFieldPK, "field1"),
|
|
||||||
[
|
|
||||||
"schema_charfieldpk_field1_0eb93b91",
|
|
||||||
"schema_charfieldpk_field1_0eb93b91_like",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific")
|
|
||||||
def test_charfield_primary_key_to_unique(self):
|
|
||||||
# Create the table and verify initial indexes.
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.create_model(CharFieldPK)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(CharFieldPK, "field1"),
|
|
||||||
["schema_charfieldpk_field1_0eb93b91_like", "schema_charfieldpk_pkey"],
|
|
||||||
)
|
|
||||||
# Alter to remove primary_key and set unique=True.
|
|
||||||
old_field1 = CharFieldPK._meta.get_field("field1")
|
|
||||||
new_field1 = CharField(unique=True, primary_key=False)
|
|
||||||
new_field1.set_attributes_from_name("field1")
|
|
||||||
new_field1.model = CharFieldPK
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(CharFieldPK, old_field1, new_field1, strict=True)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(CharFieldPK, "field1"),
|
|
||||||
[
|
|
||||||
"schema_charfieldpk_field1_0eb93b91_like",
|
|
||||||
"schema_charfieldpk_field1_0eb93b91_uniq",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific")
|
|
||||||
def test_charfield_primary_key_to_db_index_and_unique(self):
|
|
||||||
# Create the table and verify initial indexes.
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.create_model(CharFieldPK)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(CharFieldPK, "field1"),
|
|
||||||
["schema_charfieldpk_field1_0eb93b91_like", "schema_charfieldpk_pkey"],
|
|
||||||
)
|
|
||||||
# Alter to remove primary_key and set db_index=True and unique=True.
|
|
||||||
old_field1 = CharFieldPK._meta.get_field("field1")
|
|
||||||
new_field1 = CharField(unique=True, db_index=True, primary_key=False)
|
|
||||||
new_field1.set_attributes_from_name("field1")
|
|
||||||
new_field1.model = CharFieldPK
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(CharFieldPK, old_field1, new_field1, strict=True)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(CharFieldPK, "field1"),
|
|
||||||
[
|
|
||||||
"schema_charfieldpk_field1_0eb93b91_like",
|
|
||||||
"schema_charfieldpk_field1_0eb93b91_uniq",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific")
|
|
||||||
def test_charfield_primary_key_unique_to_just_unique(self):
|
|
||||||
# Create the table and verify initial indexes.
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.create_model(CharFieldPKUnique)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(CharFieldPKUnique, "field1"),
|
|
||||||
[
|
|
||||||
"schema_charfieldpkunique_field1_ffc9a22c_like",
|
|
||||||
"schema_charfieldpkunique_pkey",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
# Alter to remove primary_key (but still unique).
|
|
||||||
old_field1 = CharFieldPKUnique._meta.get_field("field1")
|
|
||||||
new_field1 = CharField(unique=True, primary_key=False)
|
|
||||||
new_field1.set_attributes_from_name("field1")
|
|
||||||
new_field1.model = CharFieldPKUnique
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(CharFieldPKUnique, old_field1, new_field1, strict=True)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(CharFieldPKUnique, "field1"),
|
|
||||||
[
|
|
||||||
"schema_charfieldpkunique_field1_ffc9a22c_like",
|
|
||||||
"schema_charfieldpkunique_field1_ffc9a22c_uniq",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific")
|
|
||||||
def test_charfield_db_index_to_textfield_db_index(self):
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.create_model(AuthorCharFieldWithIndex)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(AuthorCharFieldWithIndex, "char_field"),
|
|
||||||
[
|
|
||||||
"schema_authorcharfieldwithindex_char_field_06a11776",
|
|
||||||
"schema_authorcharfieldwithindex_char_field_06a11776_like",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
old_field = AuthorCharFieldWithIndex._meta.get_field("char_field")
|
|
||||||
new_field = TextField(db_index=True)
|
|
||||||
new_field.set_attributes_from_name("char_field")
|
|
||||||
new_field.model = AuthorCharFieldWithIndex
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(
|
|
||||||
AuthorCharFieldWithIndex, old_field, new_field, strict=True
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(AuthorCharFieldWithIndex, "char_field"),
|
|
||||||
[
|
|
||||||
"schema_authorcharfieldwithindex_char_field_06a11776",
|
|
||||||
"schema_authorcharfieldwithindex_char_field_06a11776_like",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific")
|
|
||||||
def test_charfield_change_max_length_no_index_created(self):
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.create_model(Author)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(Author, "name"),
|
|
||||||
[],
|
|
||||||
)
|
|
||||||
old_name = Author._meta.get_field("name")
|
|
||||||
new_name = CharField(max_length=20)
|
|
||||||
new_name.set_attributes_from_name("name")
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(Author, old_name, new_name, strict=True)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(Author, "name"),
|
|
||||||
[],
|
|
||||||
)
|
|
||||||
|
|
||||||
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific")
|
|
||||||
def test_remove_db_index(self):
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.create_model(AuthorCharFieldWithIndex)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(AuthorCharFieldWithIndex, "char_field"),
|
|
||||||
[
|
|
||||||
"schema_authorcharfieldwithindex_char_field_06a11776",
|
|
||||||
"schema_authorcharfieldwithindex_char_field_06a11776_like",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
old_char_field = AuthorCharFieldWithIndex._meta.get_field("char_field")
|
|
||||||
new_char_field = CharField(max_length=31, db_index=False)
|
|
||||||
new_char_field.set_attributes_from_name("char_field")
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(
|
|
||||||
AuthorCharFieldWithIndex, old_char_field, new_char_field, strict=True
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(AuthorCharFieldWithIndex, "char_field"),
|
|
||||||
[],
|
|
||||||
)
|
|
||||||
|
|
||||||
@isolate_apps("schema")
|
|
||||||
@unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific")
|
|
||||||
def test_slugfields_change_primary_key(self):
|
|
||||||
class SimpleModel(Model):
|
|
||||||
field1 = SlugField(max_length=20, primary_key=True)
|
|
||||||
field2 = SlugField(max_length=20)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
app_label = "schema"
|
|
||||||
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.create_model(SimpleModel)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(SimpleModel, "field1"),
|
|
||||||
[
|
|
||||||
"schema_simplemodel_field1_f07a3d6a_like",
|
|
||||||
"schema_simplemodel_pkey",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
# Remove primary_key from field1.
|
|
||||||
old_field1 = SimpleModel._meta.get_field("field1")
|
|
||||||
new_field1 = CharField(max_length=20, primary_key=False)
|
|
||||||
new_field1.set_attributes_from_name("field1")
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(SimpleModel, old_field1, new_field1, strict=True)
|
|
||||||
self.assertEqual(self.get_constraints_for_column(SimpleModel, "field1"), [])
|
|
||||||
# Add primary_key to field2.
|
|
||||||
old_field2 = SimpleModel._meta.get_field("field2")
|
|
||||||
new_field2 = CharField(max_length=20, primary_key=True)
|
|
||||||
new_field2.set_attributes_from_name("field2")
|
|
||||||
new_field2.model = SimpleModel
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(SimpleModel, old_field2, new_field2, strict=True)
|
|
||||||
self.assertEqual(
|
|
||||||
self.get_constraints_for_column(SimpleModel, "field2"),
|
|
||||||
[
|
|
||||||
"schema_simplemodel_field2_08772539_like",
|
|
||||||
"schema_simplemodel_field2_08772539_pk",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_alter_field_add_index_to_integerfield(self):
|
def test_alter_field_add_index_to_integerfield(self):
|
||||||
# Create the table and verify no initial indexes.
|
# Create the table and verify no initial indexes.
|
||||||
with connection.schema_editor() as editor:
|
with connection.schema_editor() as editor:
|
||||||
|
Loading…
Reference in New Issue
Block a user