Commit 375e1cfe authored by haxoza's avatar haxoza Committed by Tim Graham
Browse files

Fixed #25349 -- Allowed a ModelForm to unset a fields with blank=True, required=False.

parent 5c31d8d1
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -376,11 +376,6 @@ class BaseModelForm(BaseForm):

        exclude = self._get_validation_exclusions()

        try:
            self.instance = construct_instance(self, self.instance, opts.fields, exclude)
        except ValidationError as e:
            self._update_errors(e)

        # Foreign Keys being used to represent inline relationships
        # are excluded from basic field value validation. This is for two
        # reasons: firstly, the value may not be supplied (#12507; the
@@ -392,6 +387,11 @@ class BaseModelForm(BaseForm):
            if isinstance(field, InlineForeignKeyField):
                exclude.append(name)

        try:
            self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)
        except ValidationError as e:
            self._update_errors(e)

        try:
            self.instance.full_clean(exclude=exclude, validate_unique=False)
        except ValidationError as e:
+6 −0
Original line number Diff line number Diff line
@@ -474,3 +474,9 @@ class StrictAssignmentAll(models.Model):
        if self._should_error is True:
            raise ValidationError(message="Cannot set attribute", code='invalid')
        super(StrictAssignmentAll, self).__setattr__(key, value)


# A model with ForeignKey(blank=False, null=True)
class Award(models.Model):
    name = models.CharField(max_length=30)
    character = models.ForeignKey(Character, models.SET_NULL, blank=False, null=True)
+35 −1
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ from django.utils import six
from django.utils._os import upath

from .models import (
    Article, ArticleStatus, Author, Author1, BetterWriter, BigInt, Book,
    Article, ArticleStatus, Author, Author1, Award, BetterWriter, BigInt, Book,
    Category, Character, Colour, ColourfulItem, CommaSeparatedInteger,
    CustomErrorMessage, CustomFF, CustomFieldForExclusionModel, DateTimePost,
    DerivedBook, DerivedPost, Document, ExplicitPK, FilePathModel,
@@ -236,6 +236,40 @@ class ModelFormBaseTest(TestCase):
        obj = f2.save()
        self.assertEqual(obj.character, char)

    def test_blank_false_with_null_true_foreign_key_field(self):
        """
        A ModelForm with a model having ForeignKey(blank=False, null=True)
        and the form field set to required=False should allow the field to be
        unset.
        """
        class AwardForm(forms.ModelForm):
            class Meta:
                model = Award
                fields = '__all__'

            def __init__(self, *args, **kwargs):
                super(AwardForm, self).__init__(*args, **kwargs)
                self.fields['character'].required = False

        character = Character.objects.create(username='user', last_action=datetime.datetime.today())
        award = Award.objects.create(name='Best sprinter', character=character)
        data = {'name': 'Best tester', 'character': ''}  # remove character
        form = AwardForm(data=data, instance=award)
        self.assertTrue(form.is_valid())
        award = form.save()
        self.assertIsNone(award.character)

    def test_save_blank_false_with_required_false(self):
        """
        A ModelForm with a model with a field set to blank=False and the form
        field set to required=False should allow the field to be unset.
        """
        obj = Writer.objects.create(name='test')
        form = CustomWriterForm(data={'name': ''}, instance=obj)
        self.assertTrue(form.is_valid())
        obj = form.save()
        self.assertEqual(obj.name, '')

    def test_missing_fields_attribute(self):
        message = (
            "Creating a ModelForm without either the 'fields' attribute "