Commits

Anonymous committed afe75e8

Fixed #17615 -- Corrected unique field validation when using multitable inheritance. The validation used wrong pk value if the parent and child model had different pk fields. Thanks ungenio for the report and patch.

Comments (0)

Files changed (3)

django/db/models/base.py

 
             # Exclude the current object from the query if we are editing an
             # instance (as opposed to creating a new one)
-            if not self._state.adding and self.pk is not None:
-                qs = qs.exclude(pk=self.pk)
-
+            # Note that we need to use the pk as defined by model_class, not
+            # self.pk. These can be different fields because model inheritance
+            # allows single model to have effectively multiple primary keys.
+            # Refs #17615.
+            model_class_pk = self._get_pk_val(model_class._meta)
+            if not self._state.adding and model_class_pk is not None:
+                qs = qs.exclude(pk=model_class_pk)
             if qs.exists():
                 if len(unique_check) == 1:
                     key = unique_check[0]

tests/regressiontests/model_inheritance_regress/models.py

 
 class TrainStation(Station):
     zone = models.IntegerField()
+
+class User(models.Model):
+    username = models.CharField(max_length=30, unique=True)
+
+class Profile(User):
+    profile_id = models.AutoField(primary_key=True)
+    extra = models.CharField(max_length=30, blank=True)

tests/regressiontests/model_inheritance_regress/tests.py

 
 import datetime
 from operator import attrgetter
+from django import forms
 
 from django.test import TestCase
 
     ParkingLot2, ParkingLot3, Supplier, Wholesaler, Child, SelfRefParent,
     SelfRefChild, ArticleWithAuthor, M2MChild, QualityControl, DerivedM,
     Person, BirthdayParty, BachelorParty, MessyBachelorParty,
-    InternalCertificationAudit, BusStation, TrainStation)
+    InternalCertificationAudit, BusStation, TrainStation, User, Profile)
 
 
 class ModelInheritanceTest(TestCase):
         )
         self.assertIs(BusStation._meta.pk.model, BusStation)
         self.assertIs(TrainStation._meta.pk.model, TrainStation)
+
+    def test_inherited_unique_field_with_form(self):
+        """
+        Test that a model which has different primary key for the parent model
+        passes unique field checking correctly. Refs #17615.
+        """
+        class ProfileForm(forms.ModelForm):
+            class Meta:
+                model = Profile
+        User.objects.create(username="user_only")
+        p = Profile.objects.create(username="user_with_profile")
+        form = ProfileForm({'username': "user_with_profile", 'extra': "hello"},
+                           instance=p)
+        self.assertTrue(form.is_valid())