Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #12881: Corrected handling of inherited unique constraints. Tha…

…nks for report fgaudin.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12797 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 47a822207f937ccafe37c0b99ab37bf2157fb4f7 1 parent 883329e
Karen Tracey authored March 16, 2010
65  django/db/models/base.py
@@ -707,37 +707,50 @@ def _get_unique_checks(self, exclude=None):
707 707
         if exclude is None:
708 708
             exclude = []
709 709
         unique_checks = []
710  
-        for check in self._meta.unique_together:
711  
-            for name in check:
712  
-                # If this is an excluded field, don't add this check.
713  
-                if name in exclude:
714  
-                    break
715  
-            else:
716  
-                unique_checks.append(tuple(check))
  710
+
  711
+        unique_togethers = [(self.__class__, self._meta.unique_together)]
  712
+        for parent_class in self._meta.parents.keys():
  713
+            if parent_class._meta.unique_together:
  714
+                unique_togethers.append((parent_class, parent_class._meta.unique_together))
  715
+
  716
+        for model_class, unique_together in unique_togethers:
  717
+            for check in unique_together:
  718
+                for name in check:
  719
+                    # If this is an excluded field, don't add this check.
  720
+                    if name in exclude:
  721
+                        break
  722
+                else:
  723
+                    unique_checks.append((model_class, tuple(check)))
717 724
 
718 725
         # These are checks for the unique_for_<date/year/month>.
719 726
         date_checks = []
720 727
 
721 728
         # Gather a list of checks for fields declared as unique and add them to
722 729
         # the list of checks.
723  
-        for f in self._meta.fields:
724  
-            name = f.name
725  
-            if name in exclude:
726  
-                continue
727  
-            if f.unique:
728  
-                unique_checks.append((name,))
729  
-            if f.unique_for_date:
730  
-                date_checks.append(('date', name, f.unique_for_date))
731  
-            if f.unique_for_year:
732  
-                date_checks.append(('year', name, f.unique_for_year))
733  
-            if f.unique_for_month:
734  
-                date_checks.append(('month', name, f.unique_for_month))
  730
+
  731
+        fields_with_class = [(self.__class__, self._meta.local_fields)]
  732
+        for parent_class in self._meta.parents.keys():
  733
+            fields_with_class.append((parent_class, parent_class._meta.local_fields))
  734
+
  735
+        for model_class, fields in fields_with_class:
  736
+            for f in fields:
  737
+                name = f.name
  738
+                if name in exclude:
  739
+                    continue
  740
+                if f.unique:
  741
+                    unique_checks.append((model_class, (name,)))
  742
+                if f.unique_for_date:
  743
+                    date_checks.append((model_class, 'date', name, f.unique_for_date))
  744
+                if f.unique_for_year:
  745
+                    date_checks.append((model_class, 'year', name, f.unique_for_year))
  746
+                if f.unique_for_month:
  747
+                    date_checks.append((model_class, 'month', name, f.unique_for_month))
735 748
         return unique_checks, date_checks
736 749
 
737 750
     def _perform_unique_checks(self, unique_checks):
738 751
         errors = {}
739 752
 
740  
-        for unique_check in unique_checks:
  753
+        for model_class, unique_check in unique_checks:
741 754
             # Try to look up an existing object with the same values as this
742 755
             # object's values for all the unique field.
743 756
 
@@ -757,7 +770,7 @@ def _perform_unique_checks(self, unique_checks):
757 770
             if len(unique_check) != len(lookup_kwargs.keys()):
758 771
                 continue
759 772
 
760  
-            qs = self.__class__._default_manager.filter(**lookup_kwargs)
  773
+            qs = model_class._default_manager.filter(**lookup_kwargs)
761 774
 
762 775
             # Exclude the current object from the query if we are editing an
763 776
             # instance (as opposed to creating a new one)
@@ -769,13 +782,13 @@ def _perform_unique_checks(self, unique_checks):
769 782
                     key = unique_check[0]
770 783
                 else:
771 784
                     key = NON_FIELD_ERRORS
772  
-                errors.setdefault(key, []).append(self.unique_error_message(unique_check))
  785
+                errors.setdefault(key, []).append(self.unique_error_message(model_class, unique_check))
773 786
 
774 787
         return errors
775 788
 
776 789
     def _perform_date_checks(self, date_checks):
777 790
         errors = {}
778  
-        for lookup_type, field, unique_for in date_checks:
  791
+        for model_class, lookup_type, field, unique_for in date_checks:
779 792
             lookup_kwargs = {}
780 793
             # there's a ticket to add a date lookup, we can remove this special
781 794
             # case if that makes it's way in
@@ -788,7 +801,7 @@ def _perform_date_checks(self, date_checks):
788 801
                 lookup_kwargs['%s__%s' % (unique_for, lookup_type)] = getattr(date, lookup_type)
789 802
             lookup_kwargs[field] = getattr(self, field)
790 803
 
791  
-            qs = self.__class__._default_manager.filter(**lookup_kwargs)
  804
+            qs = model_class._default_manager.filter(**lookup_kwargs)
792 805
             # Exclude the current object from the query if we are editing an
793 806
             # instance (as opposed to creating a new one)
794 807
             if not getattr(self, '_adding', False) and self.pk is not None:
@@ -808,8 +821,8 @@ def date_error_message(self, lookup_type, field, unique_for):
808 821
             'lookup': lookup_type,
809 822
         }
810 823
 
811  
-    def unique_error_message(self, unique_check):
812  
-        opts = self._meta
  824
+    def unique_error_message(self, model_class, unique_check):
  825
+        opts = model_class._meta
813 826
         model_name = capfirst(opts.verbose_name)
814 827
 
815 828
         # A unique field
10  django/forms/models.py
@@ -488,7 +488,7 @@ def validate_unique(self):
488 488
 
489 489
         errors = []
490 490
         # Do each of the unique checks (unique and unique_together)
491  
-        for unique_check in all_unique_checks:
  491
+        for uclass, unique_check in all_unique_checks:
492 492
             seen_data = set()
493 493
             for form in self.forms:
494 494
                 # if the form doesn't have cleaned_data then we ignore it,
@@ -512,7 +512,7 @@ def validate_unique(self):
512 512
         # iterate over each of the date checks now
513 513
         for date_check in all_date_checks:
514 514
             seen_data = set()
515  
-            lookup, field, unique_for = date_check
  515
+            uclass, lookup, field, unique_for = date_check
516 516
             for form in self.forms:
517 517
                 # if the form doesn't have cleaned_data then we ignore it,
518 518
                 # it's already invalid
@@ -556,9 +556,9 @@ def get_unique_error_message(self, unique_check):
556 556
     def get_date_error_message(self, date_check):
557 557
         return ugettext("Please correct the duplicate data for %(field_name)s "
558 558
             "which must be unique for the %(lookup)s in %(date_field)s.") % {
559  
-            'field_name': date_check[1],
560  
-            'date_field': date_check[2],
561  
-            'lookup': unicode(date_check[0]),
  559
+            'field_name': date_check[2],
  560
+            'date_field': date_check[3],
  561
+            'lookup': unicode(date_check[1]),
562 562
         }
563 563
 
564 564
     def get_form_error(self):
32  tests/modeltests/model_forms/mforms.py
... ...
@@ -0,0 +1,32 @@
  1
+from django.forms import ModelForm
  2
+
  3
+from models import Product, Price, Book, DerivedBook, ExplicitPK, Post, DerivedPost
  4
+
  5
+class ProductForm(ModelForm):
  6
+    class Meta:
  7
+        model = Product
  8
+
  9
+class PriceForm(ModelForm):
  10
+    class Meta:
  11
+        model = Price
  12
+
  13
+class BookForm(ModelForm):
  14
+    class Meta:
  15
+       model = Book
  16
+
  17
+class DerivedBookForm(ModelForm):
  18
+    class Meta:
  19
+        model = DerivedBook
  20
+
  21
+class ExplicitPKForm(ModelForm):
  22
+    class Meta:
  23
+        model = ExplicitPK
  24
+        fields = ('key', 'desc',)
  25
+
  26
+class PostForm(ModelForm):
  27
+    class Meta:
  28
+        model = Post
  29
+
  30
+class DerivedPostForm(ModelForm):
  31
+    class Meta:
  32
+        model = DerivedPost
129  tests/modeltests/model_forms/models.py
@@ -101,7 +101,7 @@ def __unicode__(self):
101 101
         from PIL import Image, _imaging
102 102
     except ImportError:
103 103
         import Image, _imaging
104  
-    
  104
+
105 105
     test_images = True
106 106
 
107 107
     class ImageFile(models.Model):
@@ -181,6 +181,18 @@ class Book(models.Model):
181 181
     class Meta:
182 182
         unique_together = ('title', 'author')
183 183
 
  184
+class BookXtra(models.Model):
  185
+    isbn = models.CharField(max_length=16, unique=True)
  186
+    suffix1 = models.IntegerField(blank=True, default=0)
  187
+    suffix2 = models.IntegerField(blank=True, default=0)
  188
+
  189
+    class Meta:
  190
+        unique_together = (('suffix1', 'suffix2'))
  191
+        abstract = True
  192
+
  193
+class DerivedBook(Book, BookXtra):
  194
+    pass
  195
+
184 196
 class ExplicitPK(models.Model):
185 197
     key = models.CharField(max_length=20, primary_key=True)
186 198
     desc = models.CharField(max_length=20, blank=True, unique=True)
@@ -199,6 +211,9 @@ class Post(models.Model):
199 211
     def __unicode__(self):
200 212
         return self.name
201 213
 
  214
+class DerivedPost(Post):
  215
+    pass
  216
+
202 217
 class BigInt(models.Model):
203 218
     biggie = models.BigIntegerField()
204 219
 
@@ -1424,41 +1439,6 @@ def __unicode__(self):
1424 1439
 >>> f.cleaned_data
1425 1440
 {'field': u'1'}
1426 1441
 
1427  
-# unique/unique_together validation
1428  
-
1429  
->>> class ProductForm(ModelForm):
1430  
-...     class Meta:
1431  
-...         model = Product
1432  
->>> form = ProductForm({'slug': 'teddy-bear-blue'})
1433  
->>> form.is_valid()
1434  
-True
1435  
->>> obj = form.save()
1436  
->>> obj
1437  
-<Product: teddy-bear-blue>
1438  
->>> form = ProductForm({'slug': 'teddy-bear-blue'})
1439  
->>> form.is_valid()
1440  
-False
1441  
->>> form._errors
1442  
-{'slug': [u'Product with this Slug already exists.']}
1443  
->>> form = ProductForm({'slug': 'teddy-bear-blue'}, instance=obj)
1444  
->>> form.is_valid()
1445  
-True
1446  
-
1447  
-# ModelForm test of unique_together constraint
1448  
->>> class PriceForm(ModelForm):
1449  
-...     class Meta:
1450  
-...         model = Price
1451  
->>> form = PriceForm({'price': '6.00', 'quantity': '1'})
1452  
->>> form.is_valid()
1453  
-True
1454  
->>> form.save()
1455  
-<Price: 1 for 6.00>
1456  
->>> form = PriceForm({'price': '6.00', 'quantity': '1'})
1457  
->>> form.is_valid()
1458  
-False
1459  
->>> form._errors
1460  
-{'__all__': [u'Price with this Price and Quantity already exists.']}
1461  
-
1462 1442
 This Price instance generated by this form is not valid because the quantity
1463 1443
 field is required, but the form is valid because the field is excluded from
1464 1444
 the form. This is for backwards compatibility.
@@ -1495,51 +1475,6 @@ def __unicode__(self):
1495 1475
 >>> form.instance.pk is None
1496 1476
 True
1497 1477
 
1498  
-# Unique & unique together with null values
1499  
->>> class BookForm(ModelForm):
1500  
-...     class Meta:
1501  
-...        model = Book
1502  
->>> w = Writer.objects.get(name='Mike Royko')
1503  
->>> form = BookForm({'title': 'I May Be Wrong But I Doubt It', 'author' : w.pk})
1504  
->>> form.is_valid()
1505  
-True
1506  
->>> form.save()
1507  
-<Book: Book object>
1508  
->>> form = BookForm({'title': 'I May Be Wrong But I Doubt It', 'author' : w.pk})
1509  
->>> form.is_valid()
1510  
-False
1511  
->>> form._errors
1512  
-{'__all__': [u'Book with this Title and Author already exists.']}
1513  
->>> form = BookForm({'title': 'I May Be Wrong But I Doubt It'})
1514  
->>> form.is_valid()
1515  
-True
1516  
->>> form.save()
1517  
-<Book: Book object>
1518  
->>> form = BookForm({'title': 'I May Be Wrong But I Doubt It'})
1519  
->>> form.is_valid()
1520  
-True
1521  
-
1522  
-# Test for primary_key being in the form and failing validation.
1523  
->>> class ExplicitPKForm(ModelForm):
1524  
-...     class Meta:
1525  
-...         model = ExplicitPK
1526  
-...         fields = ('key', 'desc',)
1527  
->>> form = ExplicitPKForm({'key': u'', 'desc': u'' })
1528  
->>> form.is_valid()
1529  
-False
1530  
-
1531  
-# Ensure keys and blank character strings are tested for uniqueness.
1532  
->>> form = ExplicitPKForm({'key': u'key1', 'desc': u''})
1533  
->>> form.is_valid()
1534  
-True
1535  
->>> form.save()
1536  
-<ExplicitPK: key1>
1537  
->>> form = ExplicitPKForm({'key': u'key1', 'desc': u''})
1538  
->>> form.is_valid()
1539  
-False
1540  
->>> sorted(form.errors.items())
1541  
-[('__all__', [u'Explicit pk with this Key and Desc already exists.']), ('desc', [u'Explicit pk with this Desc already exists.']), ('key', [u'Explicit pk with this Key already exists.'])]
1542  
-
1543 1478
 # Choices on CharField and IntegerField
1544 1479
 >>> class ArticleForm(ModelForm):
1545 1480
 ...     class Meta:
@@ -1605,38 +1540,6 @@ def __unicode__(self):
1605 1540
 <tr><th><label for="id_description">Description:</label></th><td><input type="text" name="description" id="id_description" /></td></tr>
1606 1541
 <tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>
1607 1542
 
1608  
-### Validation on unique_for_date
1609  
-
1610  
->>> p = Post.objects.create(title="Django 1.0 is released", slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 9, 3))
1611  
->>> class PostForm(ModelForm):
1612  
-...     class Meta:
1613  
-...         model = Post
1614  
-
1615  
->>> f = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'})
1616  
->>> f.is_valid()
1617  
-False
1618  
->>> f.errors
1619  
-{'title': [u'Title must be unique for Posted date.']}
1620  
->>> f = PostForm({'title': "Work on Django 1.1 begins", 'posted': '2008-09-03'})
1621  
->>> f.is_valid()
1622  
-True
1623  
->>> f = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-04'})
1624  
->>> f.is_valid()
1625  
-True
1626  
->>> f = PostForm({'slug': "Django 1.0", 'posted': '2008-01-01'})
1627  
->>> f.is_valid()
1628  
-False
1629  
->>> f.errors
1630  
-{'slug': [u'Slug must be unique for Posted year.']}
1631  
->>> f = PostForm({'subtitle': "Finally", 'posted': '2008-09-30'})
1632  
->>> f.is_valid()
1633  
-False
1634  
->>> f.errors
1635  
-{'subtitle': [u'Subtitle must be unique for Posted month.']}
1636  
->>> f = PostForm({'subtitle': "Finally", "title": "Django 1.0 is released", "slug": "Django 1.0", 'posted': '2008-09-03'}, instance=p)
1637  
->>> f.is_valid()
1638  
-True
1639  
-
1640 1543
 # Clean up
1641 1544
 >>> import shutil
1642 1545
 >>> shutil.rmtree(temp_storage_dir)
141  tests/modeltests/model_forms/tests.py
... ...
@@ -1,6 +1,8 @@
  1
+import datetime
1 2
 from django.test import TestCase
2 3
 from django import forms
3  
-from models import Category
  4
+from models import Category, Writer, Book, DerivedBook, Post
  5
+from mforms import ProductForm, PriceForm, BookForm, DerivedBookForm, ExplicitPKForm, PostForm, DerivedPostForm
4 6
 
5 7
 
6 8
 class IncompleteCategoryFormWithFields(forms.ModelForm):
@@ -35,3 +37,140 @@ def test_validates_with_replaced_field_excluded(self):
35 37
         form = IncompleteCategoryFormWithExclude(data={'name': 'some name', 'slug': 'some-slug'})
36 38
         assert form.is_valid()
37 39
 
  40
+# unique/unique_together validation
  41
+class UniqueTest(TestCase):
  42
+    def setUp(self):
  43
+        self.writer = Writer.objects.create(name='Mike Royko')
  44
+
  45
+    def test_simple_unique(self):
  46
+        form = ProductForm({'slug': 'teddy-bear-blue'})
  47
+        self.assertTrue(form.is_valid())
  48
+        obj = form.save()
  49
+        form = ProductForm({'slug': 'teddy-bear-blue'})
  50
+        self.assertEqual(len(form.errors), 1)
  51
+        self.assertEqual(form.errors['slug'], [u'Product with this Slug already exists.'])
  52
+        form = ProductForm({'slug': 'teddy-bear-blue'}, instance=obj)
  53
+        self.assertTrue(form.is_valid())
  54
+
  55
+    def test_unique_together(self):
  56
+        """ModelForm test of unique_together constraint"""
  57
+        form = PriceForm({'price': '6.00', 'quantity': '1'})
  58
+        self.assertTrue(form.is_valid())
  59
+        form.save()
  60
+        form = PriceForm({'price': '6.00', 'quantity': '1'})
  61
+        self.assertFalse(form.is_valid())
  62
+        self.assertEqual(len(form.errors), 1)
  63
+        self.assertEqual(form.errors['__all__'], [u'Price with this Price and Quantity already exists.'])
  64
+
  65
+    def test_unique_null(self):
  66
+        title = 'I May Be Wrong But I Doubt It'
  67
+        form = BookForm({'title': title, 'author': self.writer.pk})
  68
+        self.assertTrue(form.is_valid())
  69
+        form.save()
  70
+        form = BookForm({'title': title, 'author': self.writer.pk})
  71
+        self.assertFalse(form.is_valid())
  72
+        self.assertEqual(len(form.errors), 1)
  73
+        self.assertEqual(form.errors['__all__'], [u'Book with this Title and Author already exists.'])
  74
+        form = BookForm({'title': title})
  75
+        self.assertTrue(form.is_valid())
  76
+        form.save()
  77
+        form = BookForm({'title': title})
  78
+        self.assertTrue(form.is_valid())
  79
+
  80
+    def test_inherited_unique(self):
  81
+        title = 'Boss'
  82
+        Book.objects.create(title=title, author=self.writer, special_id=1)
  83
+        form = DerivedBookForm({'title': 'Other', 'author': self.writer.pk, 'special_id': u'1', 'isbn': '12345'})
  84
+        self.assertFalse(form.is_valid())
  85
+        self.assertEqual(len(form.errors), 1)
  86
+        self.assertEqual(form.errors['special_id'], [u'Book with this Special id already exists.'])
  87
+
  88
+    def test_inherited_unique_together(self):
  89
+        title = 'Boss'
  90
+        form = BookForm({'title': title, 'author': self.writer.pk})
  91
+        self.assertTrue(form.is_valid())
  92
+        form.save()
  93
+        form = DerivedBookForm({'title': title, 'author': self.writer.pk, 'isbn': '12345'})
  94
+        self.assertFalse(form.is_valid())
  95
+        self.assertEqual(len(form.errors), 1)
  96
+        self.assertEqual(form.errors['__all__'], [u'Book with this Title and Author already exists.'])
  97
+
  98
+    def test_abstract_inherited_unique(self):
  99
+        title = 'Boss'
  100
+        isbn = '12345'
  101
+        dbook = DerivedBook.objects.create(title=title, author=self.writer, isbn=isbn)
  102
+        form = DerivedBookForm({'title': 'Other', 'author': self.writer.pk, 'isbn': isbn})
  103
+        self.assertFalse(form.is_valid())
  104
+        self.assertEqual(len(form.errors), 1)
  105
+        self.assertEqual(form.errors['isbn'], [u'Derived book with this Isbn already exists.'])
  106
+
  107
+    def test_abstract_inherited_unique_together(self):
  108
+        title = 'Boss'
  109
+        isbn = '12345'
  110
+        dbook = DerivedBook.objects.create(title=title, author=self.writer, isbn=isbn)
  111
+        form = DerivedBookForm({'title': 'Other', 'author': self.writer.pk, 'isbn': '9876', 'suffix1': u'0', 'suffix2': u'0'})
  112
+        self.assertFalse(form.is_valid())
  113
+        self.assertEqual(len(form.errors), 1)
  114
+        self.assertEqual(form.errors['__all__'], [u'Derived book with this Suffix1 and Suffix2 already exists.'])
  115
+
  116
+    def test_explicitpk_unspecified(self):
  117
+        """Test for primary_key being in the form and failing validation."""
  118
+        form = ExplicitPKForm({'key': u'', 'desc': u'' })
  119
+        self.assertFalse(form.is_valid())
  120
+
  121
+    def test_explicitpk_unique(self):
  122
+        """Ensure keys and blank character strings are tested for uniqueness."""
  123
+        form = ExplicitPKForm({'key': u'key1', 'desc': u''})
  124
+        self.assertTrue(form.is_valid())
  125
+        form.save()
  126
+        form = ExplicitPKForm({'key': u'key1', 'desc': u''})
  127
+        self.assertFalse(form.is_valid())
  128
+        self.assertEqual(len(form.errors), 3)
  129
+        self.assertEqual(form.errors['__all__'], [u'Explicit pk with this Key and Desc already exists.'])
  130
+        self.assertEqual(form.errors['desc'], [u'Explicit pk with this Desc already exists.'])
  131
+        self.assertEqual(form.errors['key'], [u'Explicit pk with this Key already exists.'])
  132
+
  133
+    def test_unique_for_date(self):
  134
+        p = Post.objects.create(title="Django 1.0 is released",
  135
+            slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 9, 3))
  136
+        form = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'})
  137
+        self.assertFalse(form.is_valid())
  138
+        self.assertEqual(len(form.errors), 1)
  139
+        self.assertEqual(form.errors['title'], [u'Title must be unique for Posted date.'])
  140
+        form = PostForm({'title': "Work on Django 1.1 begins", 'posted': '2008-09-03'})
  141
+        self.assertTrue(form.is_valid())
  142
+        form = PostForm({'title': "Django 1.0 is released", 'posted': '2008-09-04'})
  143
+        self.assertTrue(form.is_valid())
  144
+        form = PostForm({'slug': "Django 1.0", 'posted': '2008-01-01'})
  145
+        self.assertFalse(form.is_valid())
  146
+        self.assertEqual(len(form.errors), 1)
  147
+        self.assertEqual(form.errors['slug'], [u'Slug must be unique for Posted year.'])
  148
+        form = PostForm({'subtitle': "Finally", 'posted': '2008-09-30'})
  149
+        self.assertFalse(form.is_valid())
  150
+        self.assertEqual(form.errors['subtitle'], [u'Subtitle must be unique for Posted month.'])
  151
+        form = PostForm({'subtitle': "Finally", "title": "Django 1.0 is released",
  152
+            "slug": "Django 1.0", 'posted': '2008-09-03'}, instance=p)
  153
+        self.assertTrue(form.is_valid())
  154
+
  155
+    def test_inherited_unique_for_date(self):
  156
+        p = Post.objects.create(title="Django 1.0 is released",
  157
+            slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 9, 3))
  158
+        form = DerivedPostForm({'title': "Django 1.0 is released", 'posted': '2008-09-03'})
  159
+        self.assertFalse(form.is_valid())
  160
+        self.assertEqual(len(form.errors), 1)
  161
+        self.assertEqual(form.errors['title'], [u'Title must be unique for Posted date.'])
  162
+        form = DerivedPostForm({'title': "Work on Django 1.1 begins", 'posted': '2008-09-03'})
  163
+        self.assertTrue(form.is_valid())
  164
+        form = DerivedPostForm({'title': "Django 1.0 is released", 'posted': '2008-09-04'})
  165
+        self.assertTrue(form.is_valid())
  166
+        form = DerivedPostForm({'slug': "Django 1.0", 'posted': '2008-01-01'})
  167
+        self.assertFalse(form.is_valid())
  168
+        self.assertEqual(len(form.errors), 1)
  169
+        self.assertEqual(form.errors['slug'], [u'Slug must be unique for Posted year.'])
  170
+        form = DerivedPostForm({'subtitle': "Finally", 'posted': '2008-09-30'})
  171
+        self.assertFalse(form.is_valid())
  172
+        self.assertEqual(form.errors['subtitle'], [u'Subtitle must be unique for Posted month.'])
  173
+        form = DerivedPostForm({'subtitle': "Finally", "title": "Django 1.0 is released",
  174
+            "slug": "Django 1.0", 'posted': '2008-09-03'}, instance=p)
  175
+        self.assertTrue(form.is_valid())
  176
+
18  tests/modeltests/validation/test_unique.py
@@ -9,26 +9,34 @@ class GetUniqueCheckTests(unittest.TestCase):
9 9
     def test_unique_fields_get_collected(self):
10 10
         m = UniqueFieldsModel()
11 11
         self.assertEqual(
12  
-            ([('id',), ('unique_charfield',), ('unique_integerfield',)], []),
  12
+            ([(UniqueFieldsModel, ('id',)),
  13
+              (UniqueFieldsModel, ('unique_charfield',)),
  14
+              (UniqueFieldsModel, ('unique_integerfield',))],
  15
+             []),
13 16
             m._get_unique_checks()
14 17
         )
15 18
 
16 19
     def test_unique_together_gets_picked_up_and_converted_to_tuple(self):
17 20
         m = UniqueTogetherModel()
18 21
         self.assertEqual(
19  
-            ([('ifield', 'cfield',),('ifield', 'efield'), ('id',), ], []),
  22
+            ([(UniqueTogetherModel, ('ifield', 'cfield',)),
  23
+              (UniqueTogetherModel, ('ifield', 'efield')),
  24
+              (UniqueTogetherModel, ('id',)), ],
  25
+             []),
20 26
             m._get_unique_checks()
21 27
         )
22 28
 
23 29
     def test_primary_key_is_considered_unique(self):
24 30
         m = CustomPKModel()
25  
-        self.assertEqual(([('my_pk_field',)], []), m._get_unique_checks())
  31
+        self.assertEqual(([(CustomPKModel, ('my_pk_field',))], []), m._get_unique_checks())
26 32
 
27 33
     def test_unique_for_date_gets_picked_up(self):
28 34
         m = UniqueForDateModel()
29 35
         self.assertEqual((
30  
-            [('id',)],
31  
-            [('date', 'count', 'start_date'), ('year', 'count', 'end_date'), ('month', 'order', 'end_date')]
  36
+            [(UniqueForDateModel, ('id',))],
  37
+            [(UniqueForDateModel, 'date', 'count', 'start_date'),
  38
+             (UniqueForDateModel, 'year', 'count', 'end_date'),
  39
+             (UniqueForDateModel, 'month', 'order', 'end_date')]
32 40
             ), m._get_unique_checks()
33 41
         )
34 42
 

0 notes on commit 47a8222

Please sign in to comment.
Something went wrong with that request. Please try again.