From e7cdb0cd7eb5eb677af8dae7bfc6845186f861b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Etienne=20Chov=C3=A9?= Date: Wed, 13 Mar 2019 10:02:50 +0100 Subject: [PATCH] Fixed #30014 -- Fixed ModelChoiceField validation when initial value is a model instance. Thanks Carlton Gibson for reviews. --- django/forms/models.py | 2 ++ tests/model_forms/test_modelchoicefield.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/django/forms/models.py b/django/forms/models.py index c7e7e50885b..8b8be56b3ba 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -1248,6 +1248,8 @@ class ModelChoiceField(ChoiceField): return None try: key = self.to_field_name or 'pk' + if isinstance(value, self.queryset.model): + value = getattr(value, key) value = self.queryset.get(**{key: value}) except (ValueError, TypeError, self.queryset.model.DoesNotExist): raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice') diff --git a/tests/model_forms/test_modelchoicefield.py b/tests/model_forms/test_modelchoicefield.py index 74ef14aa73c..0591c425fe9 100644 --- a/tests/model_forms/test_modelchoicefield.py +++ b/tests/model_forms/test_modelchoicefield.py @@ -55,9 +55,18 @@ class ModelChoiceFieldTests(TestCase): with self.assertRaisesMessage(ValidationError, msg): f.clean(c4.id) + def test_clean_model_instance(self): + f = forms.ModelChoiceField(Category.objects.all()) + self.assertEqual(f.clean(self.c1), self.c1) + # An instance of incorrect model. + msg = "['Select a valid choice. That choice is not one of the available choices.']" + with self.assertRaisesMessage(ValidationError, msg): + f.clean(Book.objects.create()) + def test_clean_to_field_name(self): f = forms.ModelChoiceField(Category.objects.all(), to_field_name='slug') self.assertEqual(f.clean(self.c1.slug), self.c1) + self.assertEqual(f.clean(self.c1), self.c1) def test_choices(self): f = forms.ModelChoiceField(Category.objects.filter(pk=self.c1.id), required=False) @@ -194,6 +203,16 @@ class ModelChoiceFieldTests(TestCase): field = forms.ModelChoiceField(Author.objects.all(), disabled=True) self.assertIs(field.has_changed('x', 'y'), False) + def test_disabled_modelchoicefield_initial_model_instance(self): + class ModelChoiceForm(forms.Form): + categories = forms.ModelChoiceField( + Category.objects.all(), + disabled=True, + initial=self.c1, + ) + + self.assertTrue(ModelChoiceForm(data={'categories': self.c1.pk}).is_valid()) + def test_disabled_multiplemodelchoicefield(self): class ArticleForm(forms.ModelForm): categories = forms.ModelMultipleChoiceField(Category.objects.all(), required=False)