Author: ramiro
Date: 2011-01-12 18:15:31 -0600 (Wed, 12 Jan 2011)
New Revision: 15182

Modified:
   django/branches/releases/1.2.X/django/db/models/base.py
   django/branches/releases/1.2.X/tests/modeltests/model_forms/mforms.py
   django/branches/releases/1.2.X/tests/modeltests/model_forms/models.py
   django/branches/releases/1.2.X/tests/modeltests/model_forms/tests.py
   django/branches/releases/1.2.X/tests/modeltests/validation/models.py
   django/branches/releases/1.2.X/tests/modeltests/validation/test_unique.py
Log:
[1.2.X] Fixed #14951 -- Made the unique_for_{date,month,year} model field 
constraints to not fail when the related DateField is empty.

Existing modelforms tests were extended to cover this case and an equivalent 
set of tests was added for the model functionality.

Backport of [15167] from trunk.

Modified: django/branches/releases/1.2.X/django/db/models/base.py
===================================================================
--- django/branches/releases/1.2.X/django/db/models/base.py     2011-01-12 
23:59:49 UTC (rev 15181)
+++ django/branches/releases/1.2.X/django/db/models/base.py     2011-01-13 
00:15:31 UTC (rev 15182)
@@ -730,7 +730,7 @@
         called from a ModelForm, some fields may have been excluded; we can't
         perform a unique check on a model that is missing fields involved
         in that check.
-        Fields that did not validate should also be exluded, but they need
+        Fields that did not validate should also be excluded, but they need
         to be passed in via the exclude argument.
         """
         if exclude is None:
@@ -822,6 +822,8 @@
             # there's a ticket to add a date lookup, we can remove this special
             # case if that makes it's way in
             date = getattr(self, unique_for)
+            if date is None:
+                continue
             if lookup_type == 'date':
                 lookup_kwargs['%s__day' % unique_for] = date.day
                 lookup_kwargs['%s__month' % unique_for] = date.month

Modified: django/branches/releases/1.2.X/tests/modeltests/model_forms/mforms.py
===================================================================
--- django/branches/releases/1.2.X/tests/modeltests/model_forms/mforms.py       
2011-01-12 23:59:49 UTC (rev 15181)
+++ django/branches/releases/1.2.X/tests/modeltests/model_forms/mforms.py       
2011-01-13 00:15:31 UTC (rev 15182)
@@ -1,7 +1,8 @@
 from django import forms
 from django.forms import ModelForm
 
-from models import Product, Price, Book, DerivedBook, ExplicitPK, Post, 
DerivedPost, Writer
+from models import (Product, Price, Book, DerivedBook, ExplicitPK, Post,
+        DerivedPost, Writer, FlexibleDatePost)
 
 class ProductForm(ModelForm):
     class Meta:
@@ -37,3 +38,7 @@
 
    class Meta:
        model = Writer
+
+class FlexDatePostForm(ModelForm):
+    class Meta:
+        model = FlexibleDatePost

Modified: django/branches/releases/1.2.X/tests/modeltests/model_forms/models.py
===================================================================
--- django/branches/releases/1.2.X/tests/modeltests/model_forms/models.py       
2011-01-12 23:59:49 UTC (rev 15181)
+++ django/branches/releases/1.2.X/tests/modeltests/model_forms/models.py       
2011-01-13 00:15:31 UTC (rev 15182)
@@ -236,6 +236,12 @@
     name = models.CharField(max_length=10)
     markup = MarkupField()
 
+class FlexibleDatePost(models.Model):
+    title = models.CharField(max_length=50, unique_for_date='posted', 
blank=True)
+    slug = models.CharField(max_length=50, unique_for_year='posted', 
blank=True)
+    subtitle = models.CharField(max_length=50, unique_for_month='posted', 
blank=True)
+    posted = models.DateField(blank=True, null=True)
+
 __test__ = {'API_TESTS': """
 >>> from django import forms
 >>> from django.forms.models import ModelForm, model_to_dict

Modified: django/branches/releases/1.2.X/tests/modeltests/model_forms/tests.py
===================================================================
--- django/branches/releases/1.2.X/tests/modeltests/model_forms/tests.py        
2011-01-12 23:59:49 UTC (rev 15181)
+++ django/branches/releases/1.2.X/tests/modeltests/model_forms/tests.py        
2011-01-13 00:15:31 UTC (rev 15182)
@@ -1,9 +1,10 @@
 import datetime
 from django.test import TestCase
 from django import forms
-from models import Category, Writer, Book, DerivedBook, Post
-from mforms import (ProductForm, PriceForm, BookForm, DerivedBookForm, 
-                   ExplicitPKForm, PostForm, DerivedPostForm, CustomWriterForm)
+from models import Category, Writer, Book, DerivedBook, Post, FlexibleDatePost
+from mforms import (ProductForm, PriceForm, BookForm, DerivedBookForm,
+                   ExplicitPKForm, PostForm, DerivedPostForm, CustomWriterForm,
+                   FlexDatePostForm)
 
 
 class IncompleteCategoryFormWithFields(forms.ModelForm):
@@ -183,3 +184,16 @@
             "slug": "Django 1.0", 'posted': '2008-09-03'}, instance=p)
         self.assertTrue(form.is_valid())
 
+    def test_unique_for_date_with_nullable_date(self):
+        p = FlexibleDatePost.objects.create(title="Django 1.0 is released",
+            slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 
9, 3))
+
+        form = FlexDatePostForm({'title': "Django 1.0 is released"})
+        self.assertTrue(form.is_valid())
+        form = FlexDatePostForm({'slug': "Django 1.0"})
+        self.assertTrue(form.is_valid())
+        form = FlexDatePostForm({'subtitle': "Finally"})
+        self.assertTrue(form.is_valid())
+        form = FlexDatePostForm({'subtitle': "Finally", "title": "Django 1.0 
is released",
+            "slug": "Django 1.0"}, instance=p)
+        self.assertTrue(form.is_valid())

Modified: django/branches/releases/1.2.X/tests/modeltests/validation/models.py
===================================================================
--- django/branches/releases/1.2.X/tests/modeltests/validation/models.py        
2011-01-12 23:59:49 UTC (rev 15181)
+++ django/branches/releases/1.2.X/tests/modeltests/validation/models.py        
2011-01-13 00:15:31 UTC (rev 15182)
@@ -63,3 +63,18 @@
     def clean(self):
         if self.pub_date is None:
             self.pub_date = datetime.now()
+
+class Post(models.Model):
+    title = models.CharField(max_length=50, unique_for_date='posted', 
blank=True)
+    slug = models.CharField(max_length=50, unique_for_year='posted', 
blank=True)
+    subtitle = models.CharField(max_length=50, unique_for_month='posted', 
blank=True)
+    posted = models.DateField()
+
+    def __unicode__(self):
+        return self.name
+
+class FlexibleDatePost(models.Model):
+    title = models.CharField(max_length=50, unique_for_date='posted', 
blank=True)
+    slug = models.CharField(max_length=50, unique_for_year='posted', 
blank=True)
+    subtitle = models.CharField(max_length=50, unique_for_month='posted', 
blank=True)
+    posted = models.DateField(blank=True, null=True)

Modified: 
django/branches/releases/1.2.X/tests/modeltests/validation/test_unique.py
===================================================================
--- django/branches/releases/1.2.X/tests/modeltests/validation/test_unique.py   
2011-01-12 23:59:49 UTC (rev 15181)
+++ django/branches/releases/1.2.X/tests/modeltests/validation/test_unique.py   
2011-01-13 00:15:31 UTC (rev 15182)
@@ -1,8 +1,9 @@
 import unittest
 import datetime
 from django.conf import settings
+from django.core.exceptions import ValidationError
 from django.db import connection
-from models import CustomPKModel, UniqueTogetherModel, UniqueFieldsModel, 
UniqueForDateModel, ModelToValidate
+from models import CustomPKModel, UniqueTogetherModel, UniqueFieldsModel, 
UniqueForDateModel, ModelToValidate, Post, FlexibleDatePost
 
 
 class GetUniqueCheckTests(unittest.TestCase):
@@ -83,3 +84,74 @@
         mtv.full_clean()
         self.assertEqual(query_count, len(connection.queries))
 
+    def test_unique_for_date(self):
+        p1 = Post.objects.create(title="Django 1.0 is released",
+            slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 
9, 3))
+
+        p = Post(title="Django 1.0 is released", posted=datetime.date(2008, 9, 
3))
+        try:
+            p.full_clean()
+        except ValidationError, e:
+            self.assertEqual(e.message_dict, {'title': [u'Title must be unique 
for Posted date.']})
+        else:
+            self.fail('unique_for_date checks should catch this.')
+
+        # Should work without errors
+        p = Post(title="Work on Django 1.1 begins", posted=datetime.date(2008, 
9, 3))
+        p.full_clean()
+
+        # Should work without errors
+        p = Post(title="Django 1.0 is released", 
posted=datetime.datetime(2008, 9,4))
+        p.full_clean()
+
+        p = Post(slug="Django 1.0", posted=datetime.datetime(2008, 1, 1))
+        try:
+            p.full_clean()
+        except ValidationError, e:
+            self.assertEqual(e.message_dict, {'slug': [u'Slug must be unique 
for Posted year.']})
+        else:
+            self.fail('unique_for_year checks should catch this.')
+
+        p = Post(subtitle="Finally", posted=datetime.datetime(2008, 9, 30))
+        try:
+            p.full_clean()
+        except ValidationError, e:
+            self.assertEqual(e.message_dict, {'subtitle': [u'Subtitle must be 
unique for Posted month.']})
+        else:
+            self.fail('unique_for_month checks should catch this.')
+
+        p = Post(title="Django 1.0 is released")
+        try:
+            p.full_clean()
+        except ValidationError, e:
+            self.assertEqual(e.message_dict, {'posted': [u'This field cannot 
be null.']})
+        else:
+            self.fail("Model validation shouldn't allow an absent value for a 
DateField without null=True.")
+
+    def test_unique_for_date_with_nullable_date(self):
+        p1 = FlexibleDatePost.objects.create(title="Django 1.0 is released",
+            slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 
9, 3))
+
+        p = FlexibleDatePost(title="Django 1.0 is released")
+        try:
+            p.full_clean()
+        except ValidationError, e:
+            self.fail("unique_for_date checks shouldn't trigger when the 
associated DateField is None.")
+        except:
+            self.fail("unique_for_date checks shouldn't explode when the 
associated DateField is None.")
+
+        p = FlexibleDatePost(slug="Django 1.0")
+        try:
+            p.full_clean()
+        except ValidationError, e:
+            self.fail("unique_for_year checks shouldn't trigger when the 
associated DateField is None.")
+        except:
+            self.fail("unique_for_year checks shouldn't explode when the 
associated DateField is None.")
+
+        p = FlexibleDatePost(subtitle="Finally")
+        try:
+            p.full_clean()
+        except ValidationError, e:
+            self.fail("unique_for_month checks shouldn't trigger when the 
associated DateField is None.")
+        except:
+            self.fail("unique_for_month checks shouldn't explode when the 
associated DateField is None.")

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to