Fixed #15321 -- Honored ancestors unique checks.
Thanks to Tim for the review.
This commit is contained in:
parent
1fc458b5a3
commit
79f27f2b61
|
@ -938,7 +938,7 @@ class Model(six.with_metaclass(ModelBase)):
|
||||||
unique_checks = []
|
unique_checks = []
|
||||||
|
|
||||||
unique_togethers = [(self.__class__, self._meta.unique_together)]
|
unique_togethers = [(self.__class__, self._meta.unique_together)]
|
||||||
for parent_class in self._meta.parents.keys():
|
for parent_class in self._meta.get_parent_list():
|
||||||
if parent_class._meta.unique_together:
|
if parent_class._meta.unique_together:
|
||||||
unique_togethers.append((parent_class, parent_class._meta.unique_together))
|
unique_togethers.append((parent_class, parent_class._meta.unique_together))
|
||||||
|
|
||||||
|
@ -958,7 +958,7 @@ class Model(six.with_metaclass(ModelBase)):
|
||||||
# the list of checks.
|
# the list of checks.
|
||||||
|
|
||||||
fields_with_class = [(self.__class__, self._meta.local_fields)]
|
fields_with_class = [(self.__class__, self._meta.local_fields)]
|
||||||
for parent_class in self._meta.parents.keys():
|
for parent_class in self._meta.get_parent_list():
|
||||||
fields_with_class.append((parent_class, parent_class._meta.local_fields))
|
fields_with_class.append((parent_class, parent_class._meta.local_fields))
|
||||||
|
|
||||||
for model_class, fields in fields_with_class:
|
for model_class, fields in fields_with_class:
|
||||||
|
|
|
@ -186,3 +186,24 @@ class Base(models.Model):
|
||||||
|
|
||||||
class SubBase(Base):
|
class SubBase(Base):
|
||||||
sub_id = models.IntegerField(primary_key=True)
|
sub_id = models.IntegerField(primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
|
class GrandParent(models.Model):
|
||||||
|
first_name = models.CharField(max_length=80)
|
||||||
|
last_name = models.CharField(max_length=80)
|
||||||
|
email = models.EmailField(unique=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ('first_name', 'last_name')
|
||||||
|
|
||||||
|
|
||||||
|
class Parent(GrandParent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Child(Parent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class GrandChild(Child):
|
||||||
|
pass
|
||||||
|
|
|
@ -2,7 +2,7 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
from django.core.exceptions import FieldError
|
from django.core.exceptions import FieldError, ValidationError
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.test import TestCase, TransactionTestCase
|
from django.test import TestCase, TransactionTestCase
|
||||||
|
@ -12,7 +12,7 @@ from django.utils import six
|
||||||
from .models import (
|
from .models import (
|
||||||
Chef, CommonInfo, ItalianRestaurant, ParkingLot, Place, Post,
|
Chef, CommonInfo, ItalianRestaurant, ParkingLot, Place, Post,
|
||||||
Restaurant, Student, Supplier, Worker, MixinModel,
|
Restaurant, Student, Supplier, Worker, MixinModel,
|
||||||
Title, Copy, Base, SubBase)
|
Title, Copy, Base, SubBase, GrandParent, GrandChild)
|
||||||
|
|
||||||
|
|
||||||
class ModelInheritanceTests(TestCase):
|
class ModelInheritanceTests(TestCase):
|
||||||
|
@ -423,3 +423,33 @@ class InheritanceSameModelNameTests(TransactionTestCase):
|
||||||
def test_related_name_attribute_exists(self):
|
def test_related_name_attribute_exists(self):
|
||||||
# The Post model doesn't have an attribute called 'attached_%(app_label)s_%(class)s_set'.
|
# The Post model doesn't have an attribute called 'attached_%(app_label)s_%(class)s_set'.
|
||||||
self.assertFalse(hasattr(self.title, 'attached_%(app_label)s_%(class)s_set'))
|
self.assertFalse(hasattr(self.title, 'attached_%(app_label)s_%(class)s_set'))
|
||||||
|
|
||||||
|
|
||||||
|
class InheritanceUniqueTests(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.grand_parent = GrandParent.objects.create(
|
||||||
|
email='grand_parent@example.com',
|
||||||
|
first_name='grand',
|
||||||
|
last_name='parent',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_unique(self):
|
||||||
|
grand_child = GrandChild(
|
||||||
|
email=self.grand_parent.email,
|
||||||
|
first_name='grand',
|
||||||
|
last_name='child',
|
||||||
|
)
|
||||||
|
msg = 'Grand parent with this Email already exists.'
|
||||||
|
with self.assertRaisesMessage(ValidationError, msg):
|
||||||
|
grand_child.validate_unique()
|
||||||
|
|
||||||
|
def test_unique_together(self):
|
||||||
|
grand_child = GrandChild(
|
||||||
|
email='grand_child@example.com',
|
||||||
|
first_name=self.grand_parent.first_name,
|
||||||
|
last_name=self.grand_parent.last_name,
|
||||||
|
)
|
||||||
|
msg = 'Grand parent with this First name and Last name already exists.'
|
||||||
|
with self.assertRaisesMessage(ValidationError, msg):
|
||||||
|
grand_child.validate_unique()
|
||||||
|
|
Loading…
Reference in New Issue