Permalink
Browse files

Fixed #28542 -- Fixed deletion of primary key constraint if the new f…

…ield is unique.
  • Loading branch information...
timmartin authored and timgraham committed Sep 18, 2017
1 parent 56e590c commit 02365d3f38a64a5c2f3e932f23925a381d5bb151
Showing with 34 additions and 19 deletions.
  1. +4 −5 django/db/backends/base/schema.py
  2. +30 −14 tests/schema/tests.py
@@ -527,7 +527,7 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
# Has unique been removed?
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
- 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:
raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
len(constraint_names),
@@ -671,6 +671,9 @@ def _alter_field(self, model, old_field, new_field, old_type, new_type,
if post_actions:
for sql, params in post_actions:
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?
if (not old_field.unique and new_field.unique) or (
old_field.primary_key and not new_field.primary_key and new_field.unique
@@ -693,11 +696,7 @@ def _alter_field(self, model, old_field, new_field, 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))
# 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:
- # First, drop the old PK
- self._delete_primary_key(model, strict)
# Make the new one
self.execute(
self.sql_create_pk % {
View
@@ -1098,34 +1098,50 @@ def test_alter_int_pk_to_int_unique(self):
Should be able to rename an IntegerField(primary_key=True) to
IntegerField(unique=True).
"""
- class IntegerUnique(Model):
+ 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(primary_key=True)
+ j = IntegerField(unique=True)
class Meta:
app_label = 'schema'
apps = new_apps
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')
+ old_field = Transitional._meta.get_field('j')
new_field = IntegerField(primary_key=True)
- new_field.model = IntegerPK
+ new_field.model = Transitional
new_field.set_attributes_from_name('j')
with connection.schema_editor() as editor:
- editor.alter_field(IntegerPK, old_field, new_field, strict=True)
+ editor.alter_field(Transitional, 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')
+ # Create a model class representing the updated model.
+ class IntegerUnique(Model):
+ i = IntegerField(unique=True)
+ j = IntegerField(primary_key=True)
- with connection.schema_editor() as editor:
- editor.alter_field(IntegerPK, old_field, new_field, strict=True)
+ class Meta:
+ app_label = 'schema'
+ apps = new_apps
+ db_table = 'INTEGERPK'
# Ensure unique constraint works.
IntegerUnique.objects.create(i=1, j=1)

0 comments on commit 02365d3

Please sign in to comment.