summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRamiro Morales <cramm0@gmail.com>2011-01-13 00:15:31 +0000
committerRamiro Morales <cramm0@gmail.com>2011-01-13 00:15:31 +0000
commit0a0472f51bad24870e2bb6b89595ac922897442e (patch)
tree2099443bfcb6fc0e99e581d921e0b319e1fda418
parent0e49b8b8bda03224cef3eca1fa5f609ad50b23ad (diff)
[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. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@15182 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/db/models/base.py4
-rw-r--r--tests/modeltests/model_forms/mforms.py7
-rw-r--r--tests/modeltests/model_forms/models.py6
-rw-r--r--tests/modeltests/model_forms/tests.py20
-rw-r--r--tests/modeltests/validation/models.py15
-rw-r--r--tests/modeltests/validation/test_unique.py74
6 files changed, 120 insertions, 6 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 27117742eb..60b98ec739 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -730,7 +730,7 @@ class Model(object):
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 @@ class Model(object):
# 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
diff --git a/tests/modeltests/model_forms/mforms.py b/tests/modeltests/model_forms/mforms.py
index aef763ef62..140e8073e7 100644
--- a/tests/modeltests/model_forms/mforms.py
+++ b/tests/modeltests/model_forms/mforms.py
@@ -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 CustomWriterForm(ModelForm):
class Meta:
model = Writer
+
+class FlexDatePostForm(ModelForm):
+ class Meta:
+ model = FlexibleDatePost
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index 1087cf8795..4e7265ba74 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -236,6 +236,12 @@ class CustomFieldForExclusionModel(models.Model):
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
diff --git a/tests/modeltests/model_forms/tests.py b/tests/modeltests/model_forms/tests.py
index c5647c714f..33918ee88c 100644
--- a/tests/modeltests/model_forms/tests.py
+++ b/tests/modeltests/model_forms/tests.py
@@ -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 @@ class UniqueTest(TestCase):
"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())
diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py
index dd42936885..861d1440fe 100644
--- a/tests/modeltests/validation/models.py
+++ b/tests/modeltests/validation/models.py
@@ -63,3 +63,18 @@ class Article(models.Model):
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)
diff --git a/tests/modeltests/validation/test_unique.py b/tests/modeltests/validation/test_unique.py
index fb77c4d28c..c1d1e5dbcf 100644
--- a/tests/modeltests/validation/test_unique.py
+++ b/tests/modeltests/validation/test_unique.py
@@ -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 @@ class PerformUniqueChecksTest(unittest.TestCase):
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.")