[Django] #36201: ModelChoiceField/ModelMultipleChoiceField.clean() should catch ValidationError raised by the queryset operations

16 views
Skip to first unread message

Django

unread,
Feb 19, 2025, 10:13:52 PM2/19/25
to django-...@googlegroups.com
#36201: ModelChoiceField/ModelMultipleChoiceField.clean() should catch
ValidationError raised by the queryset operations
-------------------------------------+-------------------------------------
Reporter: Tim Graham | Type:
| Cleanup/optimization
Status: new | Component: Forms
Version: dev | Severity: Normal
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
As seen in cdc25ac4747bf5a6cdc2e70461c2d43c54529d35, `ValueError` and
`TypeError` are caught by the queryset operations in
`ModelChoiceField.clean()` and `ModelMultipleChoiceField.clean()`,
however, these exceptions are particular to
[https://github.com/django/django/blob/65c46d6932c0956d2988d13ec3d9ab3ef9d96d61/django/db/models/fields/__init__.py#L2127-L2132
IntegerFielld.get_prep_value()]. A more common implementation of
`get_prep_value()` delegates to `to_python()` which is supposed to raise
`ValidationError` for invalid values
([https://github.com/django/django/blob/65c46d6932c0956d2988d13ec3d9ab3ef9d96d61/django/db/models/fields/__init__.py#L2748-L2773
as seen in UUIDField]). Thus, `ValidationError` should also be caught so
that the
[https://github.com/django/django/blob/65c46d6932c0956d2988d13ec3d9ab3ef9d96d61/django/forms/models.py#L1566-L1570
"invalid choice"] error is raised rather than the "invalid" error of the
model field.

Aside: I discovered this while implementing `ObjectIdAutoField` in django-
mongodb-backend. I had some difficulty figuring out what exception
`get_prep_value()` should raise. I have to do some more digging to
understand if `IntegerFielld.get_prep_value()` raising `ValueError` and
`TypeError` is really appropriate, but this is the subject of another
ticket.
--
Ticket URL: <https://code.djangoproject.com/ticket/36201>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Feb 20, 2025, 3:17:33 AM2/20/25
to django-...@googlegroups.com
#36201: ModelChoiceField/ModelMultipleChoiceField.clean() should catch
ValidationError raised by the queryset operations
--------------------------------------+------------------------------------
Reporter: Tim Graham | Owner: (none)
Type: Cleanup/optimization | Status: new
Component: Forms | Version: dev
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------------+------------------------------------
Changes (by Sarah Boyce):

* stage: Unreviewed => Accepted

Comment:

Thank you! Confirmed this is inconsistently handled. The following test
fails for example:
{{{#!diff
--- a/tests/model_forms/tests.py
+++ b/tests/model_forms/tests.py
@@ -74,6 +74,7 @@ from .models import (
WriterProfile,
temp_storage_dir,
test_images,
+ UUIDPK,
)

if test_images:
@@ -2177,6 +2178,16 @@ class ModelMultipleChoiceFieldTests(TestCase):
with self.assertRaises(ValidationError):
f.clean([c6.id])

+ def test_model_multiple_choice_invalid_pk_value_error_messages(self):
+ uuid_f = forms.ModelMultipleChoiceField(UUIDPK.objects.all())
+ f = forms.ModelMultipleChoiceField(Category.objects.all())
+ for model_multiple_choice_form in [f, uuid_f]:
+ with self.assertRaisesMessage(
+ ValidationError,
+ "“invalid” is not a valid value."
+ ):
+ model_multiple_choice_form.clean(["invalid"])
+
def test_model_multiple_choice_required_false(self):
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36201#comment:1>

Django

unread,
Feb 20, 2025, 5:18:26 AM2/20/25
to django-...@googlegroups.com
#36201: ModelChoiceField/ModelMultipleChoiceField.clean() should catch
ValidationError raised by the queryset operations
-------------------------------------+-------------------------------------
Reporter: Tim Graham | Owner:
Type: | JaeHyuckSa
Cleanup/optimization | Status: assigned
Component: Forms | Version: dev
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by JaeHyuckSa):

* owner: (none) => JaeHyuckSa
* status: new => assigned

--
Ticket URL: <https://code.djangoproject.com/ticket/36201#comment:2>

Django

unread,
Feb 20, 2025, 10:55:48 AM2/20/25
to django-...@googlegroups.com
#36201: ModelChoiceField/ModelMultipleChoiceField.clean() should catch
ValidationError raised by the queryset operations
-------------------------------------+-------------------------------------
Reporter: Tim Graham | Owner:
Type: | JaeHyuckSa
Cleanup/optimization | Status: assigned
Component: Forms | Version: dev
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by JaeHyuckSa):

* has_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/36201#comment:3>

Django

unread,
Mar 7, 2025, 7:58:20 PM3/7/25
to django-...@googlegroups.com
#36201: ModelChoiceField/ModelMultipleChoiceField.clean() should catch
ValidationError raised by the queryset operations
-------------------------------------+-------------------------------------
Reporter: Tim Graham | Owner:
Type: | JaeHyuckSa
Cleanup/optimization | Status: assigned
Component: Forms | Version: dev
Severity: Normal | Resolution:
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Tim Graham):

* stage: Accepted => Ready for checkin

Comment:

Looks good. A test may be relocated per my comment.
--
Ticket URL: <https://code.djangoproject.com/ticket/36201#comment:4>

Django

unread,
Mar 10, 2025, 8:01:13 AM3/10/25
to django-...@googlegroups.com
#36201: ModelChoiceField/ModelMultipleChoiceField.clean() should catch
ValidationError raised by the queryset operations
-------------------------------------+-------------------------------------
Reporter: Tim Graham | Owner:
Type: | JaeHyuckSa
Cleanup/optimization | Status: closed
Component: Forms | Version: dev
Severity: Normal | Resolution: fixed
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce <42296566+sarahboyce@…>):

* resolution: => fixed
* status: assigned => closed

Comment:

In [changeset:"f480d5d3ed8234aea876f7eaf8a9154e5bf09d16" f480d5d3]:
{{{#!CommitTicketReference repository=""
revision="f480d5d3ed8234aea876f7eaf8a9154e5bf09d16"
Fixed #36201 -- Caught ValidationError in
ModelChoiceField/ModelMultipleChoiceField.clean().

Signed-off-by: saJaeHyukc <wogur...@gmail.com>
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36201#comment:5>
Reply all
Reply to author
Forward
0 new messages