Fixed #28542 -- Fixed deletion of primary key constraint if the new field is unique.
This commit is contained in:
parent
56e590cc0b
commit
02365d3f38
|
@ -527,7 +527,7 @@ class BaseDatabaseSchemaEditor:
|
||||||
# Has unique been removed?
|
# Has unique been removed?
|
||||||
if old_field.unique and (not new_field.unique or (not old_field.primary_key and new_field.primary_key)):
|
if old_field.unique and (not new_field.unique or (not old_field.primary_key and new_field.primary_key)):
|
||||||
# Find the unique constraint for this field
|
# Find the unique constraint for this field
|
||||||
constraint_names = self._constraint_names(model, [old_field.column], unique=True)
|
constraint_names = self._constraint_names(model, [old_field.column], unique=True, primary_key=False)
|
||||||
if strict and len(constraint_names) != 1:
|
if strict and len(constraint_names) != 1:
|
||||||
raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
|
raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
|
||||||
len(constraint_names),
|
len(constraint_names),
|
||||||
|
@ -671,6 +671,9 @@ class BaseDatabaseSchemaEditor:
|
||||||
if post_actions:
|
if post_actions:
|
||||||
for sql, params in post_actions:
|
for sql, params in post_actions:
|
||||||
self.execute(sql, params)
|
self.execute(sql, params)
|
||||||
|
# If primary_key changed to False, delete the primary key constraint.
|
||||||
|
if old_field.primary_key and not new_field.primary_key:
|
||||||
|
self._delete_primary_key(model, strict)
|
||||||
# Added a unique?
|
# Added a unique?
|
||||||
if (not old_field.unique and new_field.unique) or (
|
if (not old_field.unique and new_field.unique) or (
|
||||||
old_field.primary_key and not new_field.primary_key and new_field.unique
|
old_field.primary_key and not new_field.primary_key and new_field.unique
|
||||||
|
@ -693,11 +696,7 @@ class BaseDatabaseSchemaEditor:
|
||||||
if old_field.primary_key and new_field.primary_key and old_type != new_type:
|
if old_field.primary_key and new_field.primary_key and old_type != new_type:
|
||||||
rels_to_update.extend(_related_non_m2m_objects(old_field, new_field))
|
rels_to_update.extend(_related_non_m2m_objects(old_field, new_field))
|
||||||
# Changed to become primary key?
|
# Changed to become primary key?
|
||||||
# Note that we don't detect unsetting of a PK, as we assume another field
|
|
||||||
# will always come along and replace it.
|
|
||||||
if not old_field.primary_key and new_field.primary_key:
|
if not old_field.primary_key and new_field.primary_key:
|
||||||
# First, drop the old PK
|
|
||||||
self._delete_primary_key(model, strict)
|
|
||||||
# Make the new one
|
# Make the new one
|
||||||
self.execute(
|
self.execute(
|
||||||
self.sql_create_pk % {
|
self.sql_create_pk % {
|
||||||
|
|
|
@ -1098,6 +1098,42 @@ class SchemaTests(TransactionTestCase):
|
||||||
Should be able to rename an IntegerField(primary_key=True) to
|
Should be able to rename an IntegerField(primary_key=True) to
|
||||||
IntegerField(unique=True).
|
IntegerField(unique=True).
|
||||||
"""
|
"""
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.create_model(IntegerPK)
|
||||||
|
# Delete the old PK
|
||||||
|
old_field = IntegerPK._meta.get_field('i')
|
||||||
|
new_field = IntegerField(unique=True)
|
||||||
|
new_field.model = IntegerPK
|
||||||
|
new_field.set_attributes_from_name('i')
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.alter_field(IntegerPK, old_field, new_field, strict=True)
|
||||||
|
# The primary key constraint is gone. Result depends on database:
|
||||||
|
# 'id' for SQLite, None for others (must not be 'i').
|
||||||
|
self.assertIn(self.get_primary_key(IntegerPK._meta.db_table), ('id', None))
|
||||||
|
|
||||||
|
# Set up a model class as it currently stands. The original IntegerPK
|
||||||
|
# class is now out of date and some backends make use of the whole
|
||||||
|
# model class when modifying a field (such as sqlite3 when remaking a
|
||||||
|
# table) so an outdated model class leads to incorrect results.
|
||||||
|
class Transitional(Model):
|
||||||
|
i = IntegerField(unique=True)
|
||||||
|
j = IntegerField(unique=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'schema'
|
||||||
|
apps = new_apps
|
||||||
|
db_table = 'INTEGERPK'
|
||||||
|
|
||||||
|
# model requires a new PK
|
||||||
|
old_field = Transitional._meta.get_field('j')
|
||||||
|
new_field = IntegerField(primary_key=True)
|
||||||
|
new_field.model = Transitional
|
||||||
|
new_field.set_attributes_from_name('j')
|
||||||
|
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.alter_field(Transitional, old_field, new_field, strict=True)
|
||||||
|
|
||||||
|
# Create a model class representing the updated model.
|
||||||
class IntegerUnique(Model):
|
class IntegerUnique(Model):
|
||||||
i = IntegerField(unique=True)
|
i = IntegerField(unique=True)
|
||||||
j = IntegerField(primary_key=True)
|
j = IntegerField(primary_key=True)
|
||||||
|
@ -1107,26 +1143,6 @@ class SchemaTests(TransactionTestCase):
|
||||||
apps = new_apps
|
apps = new_apps
|
||||||
db_table = 'INTEGERPK'
|
db_table = 'INTEGERPK'
|
||||||
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.create_model(IntegerPK)
|
|
||||||
|
|
||||||
# model requires a new PK
|
|
||||||
old_field = IntegerPK._meta.get_field('j')
|
|
||||||
new_field = IntegerField(primary_key=True)
|
|
||||||
new_field.model = IntegerPK
|
|
||||||
new_field.set_attributes_from_name('j')
|
|
||||||
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(IntegerPK, old_field, new_field, strict=True)
|
|
||||||
|
|
||||||
old_field = IntegerPK._meta.get_field('i')
|
|
||||||
new_field = IntegerField(unique=True)
|
|
||||||
new_field.model = IntegerPK
|
|
||||||
new_field.set_attributes_from_name('i')
|
|
||||||
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.alter_field(IntegerPK, old_field, new_field, strict=True)
|
|
||||||
|
|
||||||
# Ensure unique constraint works.
|
# Ensure unique constraint works.
|
||||||
IntegerUnique.objects.create(i=1, j=1)
|
IntegerUnique.objects.create(i=1, j=1)
|
||||||
with self.assertRaises(IntegrityError):
|
with self.assertRaises(IntegrityError):
|
||||||
|
|
Loading…
Reference in New Issue