Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #14951 -- Made the unique_for_{date,month,year} model field con…

…straints 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.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15167 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 730769d1af383c513a104fab29bdb08dcca769f0 1 parent 30c8a55
Ramiro Morales authored January 09, 2011
4  django/db/models/base.py
@@ -648,7 +648,7 @@ def _get_unique_checks(self, exclude=None):
648 648
         called from a ModelForm, some fields may have been excluded; we can't
649 649
         perform a unique check on a model that is missing fields involved
650 650
         in that check.
651  
-        Fields that did not validate should also be exluded, but they need
  651
+        Fields that did not validate should also be excluded, but they need
652 652
         to be passed in via the exclude argument.
653 653
         """
654 654
         if exclude is None:
@@ -740,6 +740,8 @@ def _perform_date_checks(self, date_checks):
740 740
             # there's a ticket to add a date lookup, we can remove this special
741 741
             # case if that makes it's way in
742 742
             date = getattr(self, unique_for)
  743
+            if date is None:
  744
+                continue
743 745
             if lookup_type == 'date':
744 746
                 lookup_kwargs['%s__day' % unique_for] = date.day
745 747
                 lookup_kwargs['%s__month' % unique_for] = date.month
7  tests/modeltests/model_forms/mforms.py
... ...
@@ -1,7 +1,8 @@
1 1
 from django import forms
2 2
 from django.forms import ModelForm
3 3
 
4  
-from models import Product, Price, Book, DerivedBook, ExplicitPK, Post, DerivedPost, Writer
  4
+from models import (Product, Price, Book, DerivedBook, ExplicitPK, Post,
  5
+        DerivedPost, Writer, FlexibleDatePost)
5 6
 
6 7
 class ProductForm(ModelForm):
7 8
     class Meta:
@@ -37,3 +38,7 @@ class CustomWriterForm(ModelForm):
37 38
 
38 39
    class Meta:
39 40
        model = Writer
  41
+
  42
+class FlexDatePostForm(ModelForm):
  43
+    class Meta:
  44
+        model = FlexibleDatePost
6  tests/modeltests/model_forms/models.py
@@ -236,6 +236,12 @@ class CustomFieldForExclusionModel(models.Model):
236 236
     name = models.CharField(max_length=10)
237 237
     markup = MarkupField()
238 238
 
  239
+class FlexibleDatePost(models.Model):
  240
+    title = models.CharField(max_length=50, unique_for_date='posted', blank=True)
  241
+    slug = models.CharField(max_length=50, unique_for_year='posted', blank=True)
  242
+    subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True)
  243
+    posted = models.DateField(blank=True, null=True)
  244
+
239 245
 __test__ = {'API_TESTS': """
240 246
 >>> from django import forms
241 247
 >>> from django.forms.models import ModelForm, model_to_dict
20  tests/modeltests/model_forms/tests.py
... ...
@@ -1,9 +1,10 @@
1 1
 import datetime
2 2
 from django.test import TestCase
3 3
 from django import forms
4  
-from models import Category, Writer, Book, DerivedBook, Post
5  
-from mforms import (ProductForm, PriceForm, BookForm, DerivedBookForm, 
6  
-                   ExplicitPKForm, PostForm, DerivedPostForm, CustomWriterForm)
  4
+from models import Category, Writer, Book, DerivedBook, Post, FlexibleDatePost
  5
+from mforms import (ProductForm, PriceForm, BookForm, DerivedBookForm,
  6
+                   ExplicitPKForm, PostForm, DerivedPostForm, CustomWriterForm,
  7
+                   FlexDatePostForm)
7 8
 
8 9
 
9 10
 class IncompleteCategoryFormWithFields(forms.ModelForm):
@@ -183,3 +184,16 @@ def test_inherited_unique_for_date(self):
183 184
             "slug": "Django 1.0", 'posted': '2008-09-03'}, instance=p)
184 185
         self.assertTrue(form.is_valid())
185 186
 
  187
+    def test_unique_for_date_with_nullable_date(self):
  188
+        p = FlexibleDatePost.objects.create(title="Django 1.0 is released",
  189
+            slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 9, 3))
  190
+
  191
+        form = FlexDatePostForm({'title': "Django 1.0 is released"})
  192
+        self.assertTrue(form.is_valid())
  193
+        form = FlexDatePostForm({'slug': "Django 1.0"})
  194
+        self.assertTrue(form.is_valid())
  195
+        form = FlexDatePostForm({'subtitle': "Finally"})
  196
+        self.assertTrue(form.is_valid())
  197
+        form = FlexDatePostForm({'subtitle': "Finally", "title": "Django 1.0 is released",
  198
+            "slug": "Django 1.0"}, instance=p)
  199
+        self.assertTrue(form.is_valid())
15  tests/modeltests/validation/models.py
@@ -63,3 +63,18 @@ class Article(models.Model):
63 63
     def clean(self):
64 64
         if self.pub_date is None:
65 65
             self.pub_date = datetime.now()
  66
+
  67
+class Post(models.Model):
  68
+    title = models.CharField(max_length=50, unique_for_date='posted', blank=True)
  69
+    slug = models.CharField(max_length=50, unique_for_year='posted', blank=True)
  70
+    subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True)
  71
+    posted = models.DateField()
  72
+
  73
+    def __unicode__(self):
  74
+        return self.name
  75
+
  76
+class FlexibleDatePost(models.Model):
  77
+    title = models.CharField(max_length=50, unique_for_date='posted', blank=True)
  78
+    slug = models.CharField(max_length=50, unique_for_year='posted', blank=True)
  79
+    subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True)
  80
+    posted = models.DateField(blank=True, null=True)
75  tests/modeltests/validation/test_unique.py
... ...
@@ -1,12 +1,13 @@
1 1
 import datetime
2 2
 
3 3
 from django.conf import settings
  4
+from django.core.exceptions import ValidationError
4 5
 from django.db import connection
5 6
 from django.test import TestCase
6 7
 from django.utils import unittest
7 8
 
8 9
 from models import (CustomPKModel, UniqueTogetherModel, UniqueFieldsModel,
9  
-    UniqueForDateModel, ModelToValidate)
  10
+    UniqueForDateModel, ModelToValidate, Post, FlexibleDatePost)
10 11
 
11 12
 
12 13
 class GetUniqueCheckTests(unittest.TestCase):
@@ -76,3 +77,75 @@ def test():
76 77
             mtv = ModelToValidate(number=10, name='Some Name')
77 78
             mtv.full_clean()
78 79
         self.assertNumQueries(0, test)
  80
+
  81
+    def test_unique_for_date(self):
  82
+        p1 = Post.objects.create(title="Django 1.0 is released",
  83
+            slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 9, 3))
  84
+
  85
+        p = Post(title="Django 1.0 is released", posted=datetime.date(2008, 9, 3))
  86
+        try:
  87
+            p.full_clean()
  88
+        except ValidationError, e:
  89
+            self.assertEqual(e.message_dict, {'title': [u'Title must be unique for Posted date.']})
  90
+        else:
  91
+            self.fail('unique_for_date checks should catch this.')
  92
+
  93
+        # Should work without errors
  94
+        p = Post(title="Work on Django 1.1 begins", posted=datetime.date(2008, 9, 3))
  95
+        p.full_clean()
  96
+
  97
+        # Should work without errors
  98
+        p = Post(title="Django 1.0 is released", posted=datetime.datetime(2008, 9,4))
  99
+        p.full_clean()
  100
+
  101
+        p = Post(slug="Django 1.0", posted=datetime.datetime(2008, 1, 1))
  102
+        try:
  103
+            p.full_clean()
  104
+        except ValidationError, e:
  105
+            self.assertEqual(e.message_dict, {'slug': [u'Slug must be unique for Posted year.']})
  106
+        else:
  107
+            self.fail('unique_for_year checks should catch this.')
  108
+
  109
+        p = Post(subtitle="Finally", posted=datetime.datetime(2008, 9, 30))
  110
+        try:
  111
+            p.full_clean()
  112
+        except ValidationError, e:
  113
+            self.assertEqual(e.message_dict, {'subtitle': [u'Subtitle must be unique for Posted month.']})
  114
+        else:
  115
+            self.fail('unique_for_month checks should catch this.')
  116
+
  117
+        p = Post(title="Django 1.0 is released")
  118
+        try:
  119
+            p.full_clean()
  120
+        except ValidationError, e:
  121
+            self.assertEqual(e.message_dict, {'posted': [u'This field cannot be null.']})
  122
+        else:
  123
+            self.fail("Model validation shouldn't allow an absent value for a DateField without null=True.")
  124
+
  125
+    def test_unique_for_date_with_nullable_date(self):
  126
+        p1 = FlexibleDatePost.objects.create(title="Django 1.0 is released",
  127
+            slug="Django 1.0", subtitle="Finally", posted=datetime.date(2008, 9, 3))
  128
+
  129
+        p = FlexibleDatePost(title="Django 1.0 is released")
  130
+        try:
  131
+            p.full_clean()
  132
+        except ValidationError, e:
  133
+            self.fail("unique_for_date checks shouldn't trigger when the associated DateField is None.")
  134
+        except:
  135
+            self.fail("unique_for_date checks shouldn't explode when the associated DateField is None.")
  136
+
  137
+        p = FlexibleDatePost(slug="Django 1.0")
  138
+        try:
  139
+            p.full_clean()
  140
+        except ValidationError, e:
  141
+            self.fail("unique_for_year checks shouldn't trigger when the associated DateField is None.")
  142
+        except:
  143
+            self.fail("unique_for_year checks shouldn't explode when the associated DateField is None.")
  144
+
  145
+        p = FlexibleDatePost(subtitle="Finally")
  146
+        try:
  147
+            p.full_clean()
  148
+        except ValidationError, e:
  149
+            self.fail("unique_for_month checks shouldn't trigger when the associated DateField is None.")
  150
+        except:
  151
+            self.fail("unique_for_month checks shouldn't explode when the associated DateField is None.")

0 notes on commit 730769d

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