diff --git a/django/forms/forms.py b/django/forms/forms.py
index f868165..38da218 100644
a
|
b
|
class BaseForm(object):
|
159 | 159 | Returns True if the form has no errors. Otherwise, False. If errors are |
160 | 160 | being ignored, returns False. |
161 | 161 | """ |
162 | | return self.is_bound and not self.errors |
| 162 | try: |
| 163 | return self.is_bound and not self.errors |
| 164 | except ValueError as e: |
| 165 | self.add_error(None, e) |
| 166 | return False |
163 | 167 | |
164 | 168 | def add_prefix(self, field_name): |
165 | 169 | """ |
diff --git a/tests/model_forms/models.py b/tests/model_forms/models.py
index e71c482..60d33d6 100644
a
|
b
|
class Character(models.Model):
|
401 | 401 | class StumpJoke(models.Model): |
402 | 402 | most_recently_fooled = models.ForeignKey(Character, limit_choices_to=today_callable_dict, related_name="+") |
403 | 403 | has_fooled_today = models.ManyToManyField(Character, limit_choices_to=today_callable_q, related_name="+") |
| 404 | |
| 405 | |
| 406 | #Models for #13776 |
| 407 | |
| 408 | |
| 409 | class User(models.Model): |
| 410 | name = models.CharField(max_length=30) |
| 411 | phone = models.IntegerField(max_length=11) |
| 412 | |
| 413 | |
| 414 | class Student(models.Model): |
| 415 | user = models.ForeignKey(User) |
| 416 | std = models.CharField(max_length=30, null=True) |
diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py
index c3b4c33..620e276 100644
a
|
b
|
from .models import (Article, ArticleStatus, Author, Author1, BetterWriter, BigI
|
23 | 23 | ImprovedArticle, ImprovedArticleWithParentLink, Inventory, Person, Post, Price, |
24 | 24 | Product, Publication, TextFile, Triple, Writer, WriterProfile, |
25 | 25 | Colour, ColourfulItem, DateTimePost, CustomErrorMessage, |
26 | | test_images, StumpJoke, Character) |
| 26 | test_images, StumpJoke, Character, Student) |
27 | 27 | |
28 | 28 | if test_images: |
29 | 29 | from .models import ImageFile, OptionalImageFile |
… |
… |
class CustomErrorMessageForm(forms.ModelForm):
|
161 | 161 | model = CustomErrorMessage |
162 | 162 | |
163 | 163 | |
| 164 | #Form for testing #13776 |
| 165 | class FormForTestingIsValid(forms.ModelForm): |
| 166 | class Meta: |
| 167 | model = Student |
| 168 | exclude = [] |
| 169 | |
| 170 | def __init__(self, *a, **k): |
| 171 | super(FormForTestingIsValid, self).__init__(*a, **k) |
| 172 | for field in self.fields: |
| 173 | self.fields[field].required = False |
| 174 | |
| 175 | |
164 | 176 | class ModelFormBaseTest(TestCase): |
165 | 177 | def test_base_form(self): |
166 | 178 | self.assertEqual(list(BaseCategoryForm.base_fields), |
… |
… |
class ModelFormBaseTest(TestCase):
|
339 | 351 | model = Category |
340 | 352 | exclude = ('url') # note the missing comma |
341 | 353 | |
| 354 | def test_blank_with_null_foreign_key_field(self): |
| 355 | data = {'std': 'Engineering'} |
| 356 | f1 = FormForTestingIsValid() |
| 357 | self.assertTrue(not f1.is_valid()) # form not valid because its not bound |
| 358 | self.assertEqual(f1.errors, {}) |
| 359 | |
| 360 | f2 = FormForTestingIsValid(data) |
| 361 | self.assertTrue(not f2.is_valid()) # form not valid because FK is not specified even when null=False |
| 362 | self.assertTrue('Cannot assign None: "Student.user" does not allow null values.' in f2.errors.values()[0]) |
| 363 | with self.assertRaisesMessage(ValueError, "The Student could not be created because the data didn't validate."): |
| 364 | f2.save() # the message displayed shows that error was identified while running is_valid() and not save() |
| 365 | |
| 366 | f3 = FormForTestingIsValid(data) |
| 367 | with self.assertRaisesMessage(ValueError, 'Cannot assign None: "Student.user" does not allow null values.'): |
| 368 | f3.save() # the message displayed shows that error was identified when save() was run |
| 369 | |
342 | 370 | def test_exclude_and_validation(self): |
343 | 371 | # This Price instance generated by this form is not valid because the quantity |
344 | 372 | # field is required, but the form is valid because the field is excluded from |