1 | diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
|
---|
2 | index 13cec1b..cae7525 100644
|
---|
3 | --- a/django/db/models/fields/__init__.py
|
---|
4 | +++ b/django/db/models/fields/__init__.py
|
---|
5 | @@ -1028,6 +1028,7 @@ class FloatField(Field):
|
---|
6 |
|
---|
7 | class IntegerField(Field):
|
---|
8 | empty_strings_allowed = False
|
---|
9 | + empty_values = [None]
|
---|
10 | default_error_messages = {
|
---|
11 | 'invalid': _("'%s' value must be an integer."),
|
---|
12 | }
|
---|
13 | diff --git a/tests/forms_tests/models.py b/tests/forms_tests/models.py
|
---|
14 | index bec31d1..6c8d931 100644
|
---|
15 | --- a/tests/forms_tests/models.py
|
---|
16 | +++ b/tests/forms_tests/models.py
|
---|
17 | @@ -27,7 +27,7 @@ def callable_default():
|
---|
18 |
|
---|
19 | class Defaults(models.Model):
|
---|
20 | name = models.CharField(max_length=255, default='class default value')
|
---|
21 | - def_date = models.DateField(default = datetime.date(1980, 1, 1))
|
---|
22 | + def_date = models.DateField(default=datetime.date(1980, 1, 1))
|
---|
23 | value = models.IntegerField(default=42)
|
---|
24 | callable_default = models.IntegerField(default=callable_default)
|
---|
25 |
|
---|
26 | @@ -63,6 +63,7 @@ class ChoiceFieldModel(models.Model):
|
---|
27 | multi_choice_int = models.ManyToManyField(ChoiceOptionModel, blank=False, related_name='multi_choice_int',
|
---|
28 | default=lambda: [1])
|
---|
29 |
|
---|
30 | +
|
---|
31 | class OptionalMultiChoiceModel(models.Model):
|
---|
32 | multi_choice = models.ManyToManyField(ChoiceOptionModel, blank=False, related_name='not_relevant',
|
---|
33 | default=lambda: ChoiceOptionModel.objects.filter(name='default'))
|
---|
34 | diff --git a/tests/model_forms/models.py b/tests/model_forms/models.py
|
---|
35 | index a79d9b8..75a1a5f 100644
|
---|
36 | --- a/tests/model_forms/models.py
|
---|
37 | +++ b/tests/model_forms/models.py
|
---|
38 | @@ -78,7 +78,7 @@ class BetterAuthor(Author):
|
---|
39 | @python_2_unicode_compatible
|
---|
40 | class AuthorProfile(models.Model):
|
---|
41 | writer = models.OneToOneField(Author, primary_key=True)
|
---|
42 | - age = models.PositiveIntegerField()
|
---|
43 | + age = models.PositiveIntegerField(blank=True, null=True)
|
---|
44 |
|
---|
45 | def __str__(self):
|
---|
46 | return "%s is %s" % (self.writer, self.age)
|
---|
47 | diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py
|
---|
48 | index c5db011..a5bb76e 100644
|
---|
49 | --- a/tests/model_forms/tests.py
|
---|
50 | +++ b/tests/model_forms/tests.py
|
---|
51 | @@ -28,12 +28,12 @@ from .models import (Article, ArticleStatus, BetterAuthor, BigInt,
|
---|
52 |
|
---|
53 | if test_images:
|
---|
54 | from .models import ImageFile, OptionalImageFile
|
---|
55 | +
|
---|
56 | class ImageFileForm(forms.ModelForm):
|
---|
57 | class Meta:
|
---|
58 | model = ImageFile
|
---|
59 | fields = '__all__'
|
---|
60 |
|
---|
61 | -
|
---|
62 | class OptionalImageFileForm(forms.ModelForm):
|
---|
63 | class Meta:
|
---|
64 | model = OptionalImageFile
|
---|
65 | @@ -83,11 +83,11 @@ class DerivedPostForm(forms.ModelForm):
|
---|
66 |
|
---|
67 |
|
---|
68 | class CustomAuthorForm(forms.ModelForm):
|
---|
69 | - name = forms.CharField(required=False)
|
---|
70 | + name = forms.CharField(required=False)
|
---|
71 |
|
---|
72 | - class Meta:
|
---|
73 | - model = Author
|
---|
74 | - fields = '__all__'
|
---|
75 | + class Meta:
|
---|
76 | + model = Author
|
---|
77 | + fields = '__all__'
|
---|
78 |
|
---|
79 |
|
---|
80 | class FlexDatePostForm(forms.ModelForm):
|
---|
81 | @@ -117,7 +117,7 @@ class ArticleForm(forms.ModelForm):
|
---|
82 | class PartialArticleForm(forms.ModelForm):
|
---|
83 | class Meta:
|
---|
84 | model = Article
|
---|
85 | - fields = ('headline','pub_date')
|
---|
86 | + fields = ('headline', 'pub_date')
|
---|
87 |
|
---|
88 |
|
---|
89 | class RoykoForm(forms.ModelForm):
|
---|
90 | @@ -212,6 +212,7 @@ class ModelFormWithMedia(forms.ModelForm):
|
---|
91 | css = {
|
---|
92 | 'all': ('/some/form/css',)
|
---|
93 | }
|
---|
94 | +
|
---|
95 | class Meta:
|
---|
96 | model = TextFile
|
---|
97 | fields = '__all__'
|
---|
98 | @@ -241,7 +242,7 @@ class ModelFormBaseTest(TestCase):
|
---|
99 | ['name', 'slug', 'url'])
|
---|
100 |
|
---|
101 | def test_missing_fields_attribute(self):
|
---|
102 | - with warnings.catch_warnings(record=True) as w:
|
---|
103 | + with warnings.catch_warnings(record=True):
|
---|
104 | warnings.simplefilter("always", PendingDeprecationWarning)
|
---|
105 |
|
---|
106 | class MissingFieldsForm(forms.ModelForm):
|
---|
107 | @@ -275,7 +276,7 @@ class ModelFormBaseTest(TestCase):
|
---|
108 | fields = '__all__'
|
---|
109 |
|
---|
110 | self.assertTrue(isinstance(ReplaceField.base_fields['url'],
|
---|
111 | - forms.fields.BooleanField))
|
---|
112 | + forms.fields.BooleanField))
|
---|
113 |
|
---|
114 | def test_replace_field_variant_2(self):
|
---|
115 | # Should have the same result as before,
|
---|
116 | @@ -288,7 +289,7 @@ class ModelFormBaseTest(TestCase):
|
---|
117 | fields = ['url']
|
---|
118 |
|
---|
119 | self.assertTrue(isinstance(ReplaceField.base_fields['url'],
|
---|
120 | - forms.fields.BooleanField))
|
---|
121 | + forms.fields.BooleanField))
|
---|
122 |
|
---|
123 | def test_replace_field_variant_3(self):
|
---|
124 | # Should have the same result as before,
|
---|
125 | @@ -301,7 +302,7 @@ class ModelFormBaseTest(TestCase):
|
---|
126 | fields = [] # url will still appear, since it is explicit above
|
---|
127 |
|
---|
128 | self.assertTrue(isinstance(ReplaceField.base_fields['url'],
|
---|
129 | - forms.fields.BooleanField))
|
---|
130 | + forms.fields.BooleanField))
|
---|
131 |
|
---|
132 | def test_override_field(self):
|
---|
133 | class AuthorForm(forms.ModelForm):
|
---|
134 | @@ -430,11 +431,11 @@ class ModelFormBaseTest(TestCase):
|
---|
135 |
|
---|
136 | def test_subclassmeta_form(self):
|
---|
137 | class SomeCategoryForm(forms.ModelForm):
|
---|
138 | - checkbox = forms.BooleanField()
|
---|
139 | + checkbox = forms.BooleanField()
|
---|
140 |
|
---|
141 | - class Meta:
|
---|
142 | - model = Category
|
---|
143 | - fields = '__all__'
|
---|
144 | + class Meta:
|
---|
145 | + model = Category
|
---|
146 | + fields = '__all__'
|
---|
147 |
|
---|
148 | class SubclassMeta(SomeCategoryForm):
|
---|
149 | """ We can also subclass the Meta inner class to change the fields
|
---|
150 | @@ -485,7 +486,6 @@ class TestWidgetForm(forms.ModelForm):
|
---|
151 | }
|
---|
152 |
|
---|
153 |
|
---|
154 | -
|
---|
155 | class TestWidgets(TestCase):
|
---|
156 | def test_base_widgets(self):
|
---|
157 | frm = TestWidgetForm()
|
---|
158 | @@ -514,6 +514,7 @@ class IncompleteCategoryFormWithFields(forms.ModelForm):
|
---|
159 | fields = ('name', 'slug')
|
---|
160 | model = Category
|
---|
161 |
|
---|
162 | +
|
---|
163 | class IncompleteCategoryFormWithExclude(forms.ModelForm):
|
---|
164 | """
|
---|
165 | A form that replaces the model's url field with a custom one. This should
|
---|
166 | @@ -540,7 +541,16 @@ class ValidationTest(TestCase):
|
---|
167 | assert form.is_valid()
|
---|
168 |
|
---|
169 |
|
---|
170 | +class PositiveintegerModelTest(TestCase):
|
---|
171 | + def setUp(self):
|
---|
172 | + self.author = Author.objects.create(name='Mike Royko')
|
---|
173 |
|
---|
174 | + def test_full_clean_positiveinteger_emptystring(self):
|
---|
175 | + art = AuthorProfile(
|
---|
176 | + writer=self.author,
|
---|
177 | + age=''
|
---|
178 | + )
|
---|
179 | + self.assertRaises(ValidationError, art.full_clean)
|
---|
180 |
|
---|
181 | # unique/unique_together validation
|
---|
182 | class UniqueTest(TestCase):
|
---|
183 | @@ -601,7 +611,7 @@ class UniqueTest(TestCase):
|
---|
184 | def test_abstract_inherited_unique(self):
|
---|
185 | title = 'Boss'
|
---|
186 | isbn = '12345'
|
---|
187 | - dbook = DerivedBook.objects.create(title=title, author=self.author, isbn=isbn,
|
---|
188 | + DerivedBook.objects.create(title=title, author=self.author, isbn=isbn,
|
---|
189 | pubdate='2012-12-12 00:00')
|
---|
190 | form = DerivedBookForm({'title': 'Other', 'author': self.author.pk, 'isbn': isbn})
|
---|
191 | self.assertFalse(form.is_valid())
|
---|
192 | @@ -611,15 +621,15 @@ class UniqueTest(TestCase):
|
---|
193 | def test_abstract_inherited_unique_together(self):
|
---|
194 | title = 'Boss'
|
---|
195 | isbn = '12345'
|
---|
196 | - dbook = DerivedBook.objects.create(title=title, author=self.author, isbn=isbn,
|
---|
197 | + DerivedBook.objects.create(title=title, author=self.author, isbn=isbn,
|
---|
198 | pubdate='2012-12-12 00:00')
|
---|
199 | form = DerivedBookForm({
|
---|
200 | - 'title': 'Other',
|
---|
201 | - 'author': self.author.pk,
|
---|
202 | - 'isbn': '9876',
|
---|
203 | - 'suffix1': '0',
|
---|
204 | - 'suffix2': '0'
|
---|
205 | - })
|
---|
206 | + 'title': 'Other',
|
---|
207 | + 'author': self.author.pk,
|
---|
208 | + 'isbn': '9876',
|
---|
209 | + 'suffix1': '0',
|
---|
210 | + 'suffix2': '0'
|
---|
211 | + })
|
---|
212 | self.assertFalse(form.is_valid())
|
---|
213 | self.assertEqual(len(form.errors), 1)
|
---|
214 | self.assertEqual(form.errors['__all__'],
|
---|
215 | @@ -627,7 +637,7 @@ class UniqueTest(TestCase):
|
---|
216 |
|
---|
217 | def test_explicitpk_unspecified(self):
|
---|
218 | """Test for primary_key being in the form and failing validation."""
|
---|
219 | - form = ExplicitPKForm({'key': '', 'desc': '' })
|
---|
220 | + form = ExplicitPKForm({'key': '', 'desc': ''})
|
---|
221 | self.assertFalse(form.is_valid())
|
---|
222 |
|
---|
223 | def test_explicitpk_unique(self):
|
---|
224 | @@ -704,12 +714,13 @@ class UniqueTest(TestCase):
|
---|
225 | "slug": "Django 1.0"}, instance=p)
|
---|
226 | self.assertTrue(form.is_valid())
|
---|
227 |
|
---|
228 | +
|
---|
229 | class ModelToDictTests(TestCase):
|
---|
230 | """
|
---|
231 | Tests for forms.models.model_to_dict
|
---|
232 | """
|
---|
233 | def test_model_to_dict_many_to_many(self):
|
---|
234 | - categories=[
|
---|
235 | + categories = [
|
---|
236 | Category(name='TestName1', slug='TestName1', url='url1'),
|
---|
237 | Category(name='TestName2', slug='TestName2', url='url2'),
|
---|
238 | Category(name='TestName3', slug='TestName3', url='url3')
|
---|
239 | @@ -740,6 +751,7 @@ class ModelToDictTests(TestCase):
|
---|
240 | #Ensure many-to-many relation appears as a list
|
---|
241 | self.assertIsInstance(d['categories'], list)
|
---|
242 |
|
---|
243 | +
|
---|
244 | class OldFormForXTests(TestCase):
|
---|
245 | def test_base_form(self):
|
---|
246 | self.assertEqual(Category.objects.count(), 0)
|
---|
247 | @@ -871,12 +883,12 @@ class OldFormForXTests(TestCase):
|
---|
248 | self.assertHTMLEqual(six.text_type(f), '''<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="100" /><br /><span class="helptext">Use both first and last names.</span></td></tr>''')
|
---|
249 |
|
---|
250 | art = Article(
|
---|
251 | - headline='Test article',
|
---|
252 | - slug='test-article',
|
---|
253 | - pub_date=datetime.date(1988, 1, 4),
|
---|
254 | - writer=w,
|
---|
255 | - article='Hello.'
|
---|
256 | - )
|
---|
257 | + headline='Test article',
|
---|
258 | + slug='test-article',
|
---|
259 | + pub_date=datetime.date(1988, 1, 4),
|
---|
260 | + writer=w,
|
---|
261 | + article='Hello.'
|
---|
262 | + )
|
---|
263 | art.save()
|
---|
264 | art_id_1 = art.id
|
---|
265 | self.assertEqual(art_id_1 is not None, True)
|
---|
266 | @@ -958,11 +970,11 @@ class OldFormForXTests(TestCase):
|
---|
267 |
|
---|
268 | # Initial values can be provided for model forms
|
---|
269 | f = TestArticleForm(
|
---|
270 | - auto_id=False,
|
---|
271 | - initial={
|
---|
272 | - 'headline': 'Your headline here',
|
---|
273 | - 'categories': [str(c1.id), str(c2.id)]
|
---|
274 | - })
|
---|
275 | + auto_id=False,
|
---|
276 | + initial={
|
---|
277 | + 'headline': 'Your headline here',
|
---|
278 | + 'categories': [str(c1.id), str(c2.id)]
|
---|
279 | + })
|
---|
280 | self.assertHTMLEqual(f.as_ul(), '''<li>Headline: <input type="text" name="headline" value="Your headline here" maxlength="50" /></li>
|
---|
281 | <li>Slug: <input type="text" name="slug" maxlength="50" /></li>
|
---|
282 | <li>Pub date: <input type="text" name="pub_date" /></li>
|
---|
283 | @@ -1640,6 +1652,7 @@ class OldFormForXTests(TestCase):
|
---|
284 |
|
---|
285 | class CategoryForm(forms.ModelForm):
|
---|
286 | description = forms.CharField()
|
---|
287 | +
|
---|
288 | class Meta:
|
---|
289 | model = Category
|
---|
290 | fields = ['description', 'url']
|
---|
291 | @@ -1666,7 +1679,7 @@ class OldFormForXTests(TestCase):
|
---|
292 | self.assertHTMLEqual(six.text_type(CustomFieldForExclusionForm()),
|
---|
293 | '''<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="10" /></td></tr>''')
|
---|
294 |
|
---|
295 | - def test_iterable_model_m2m(self) :
|
---|
296 | + def test_iterable_model_m2m(self):
|
---|
297 | colour = Colour.objects.create(name='Blue')
|
---|
298 | form = ColourfulItemForm()
|
---|
299 | self.maxDiff = 1024
|
---|