From 38ad710aba885ad26944ff5708ce1a02a446d2d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20L=C3=B6tvall?= Date: Sat, 8 Jun 2024 12:14:46 +0200 Subject: [PATCH] Fixed #35483 -- Added NUL (0x00) character validation to ModelChoiceFields. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applied the ProhibitNullCharactersValidator to ModelChoiceField and ModelMultipleChoiceField. Co-authored-by: Viktor Paripás Co-authored-by: Vasyl Dizhak Co-authored-by: Arthur Vasconcelos --- django/forms/models.py | 7 +++++++ tests/model_forms/test_modelchoicefield.py | 8 +++++++- tests/model_forms/tests.py | 9 +++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/django/forms/models.py b/django/forms/models.py index 09be448984e1..8084e16c8d98 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -11,6 +11,7 @@ ImproperlyConfigured, ValidationError, ) +from django.core.validators import ProhibitNullCharactersValidator from django.db.models.utils import AltersData from django.forms.fields import ChoiceField, Field from django.forms.forms import BaseForm, DeclarativeFieldsMetaclass @@ -1487,6 +1488,10 @@ def __init__( self.limit_choices_to = limit_choices_to # limit the queryset later. self.to_field_name = to_field_name + def validate_no_null_characters(self, value): + non_null_character_validator = ProhibitNullCharactersValidator() + return non_null_character_validator(value) + def get_limit_choices_to(self): """ Return ``limit_choices_to`` for this form field. @@ -1551,6 +1556,7 @@ def prepare_value(self, value): def to_python(self, value): if value in self.empty_values: return None + self.validate_no_null_characters(value) try: key = self.to_field_name or "pk" if isinstance(value, self.queryset.model): @@ -1631,6 +1637,7 @@ def _check_values(self, value): code="invalid_list", ) for pk in value: + self.validate_no_null_characters(pk) try: self.queryset.filter(**{key: pk}) except (ValueError, TypeError): diff --git a/tests/model_forms/test_modelchoicefield.py b/tests/model_forms/test_modelchoicefield.py index 19e9db69a058..83d801768aca 100644 --- a/tests/model_forms/test_modelchoicefield.py +++ b/tests/model_forms/test_modelchoicefield.py @@ -7,7 +7,7 @@ from django.template import Context, Template from django.test import TestCase -from .models import Article, Author, Book, Category, Writer +from .models import Article, Author, Book, Category, ExplicitPK, Writer class ModelChoiceFieldTests(TestCase): @@ -79,6 +79,12 @@ def test_clean_to_field_name(self): self.assertEqual(f.clean(self.c1.slug), self.c1) self.assertEqual(f.clean(self.c1), self.c1) + def test_model_choice_null_characters(self): + f = forms.ModelChoiceField(queryset=ExplicitPK.objects.all()) + msg = "Null characters are not allowed." + with self.assertRaisesMessage(ValidationError, msg): + f.clean("\x00something") + def test_choices(self): f = forms.ModelChoiceField( Category.objects.filter(pk=self.c1.id), required=False diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py index 3f927cb0534c..c6e12e1aab51 100644 --- a/tests/model_forms/tests.py +++ b/tests/model_forms/tests.py @@ -2227,6 +2227,15 @@ def test_model_multiple_choice_number_of_queries(self): f = forms.ModelMultipleChoiceField(queryset=Writer.objects.all()) self.assertNumQueries(1, f.clean, [p.pk for p in persons[1:11:2]]) + def test_model_multiple_choice_null_characters(self): + f = forms.ModelMultipleChoiceField(queryset=ExplicitPK.objects.all()) + msg = "Null characters are not allowed." + with self.assertRaisesMessage(ValidationError, msg): + f.clean(["\x00something"]) + + with self.assertRaisesMessage(ValidationError, msg): + f.clean(["valid", "\x00something"]) + def test_model_multiple_choice_run_validators(self): """ ModelMultipleChoiceField run given validators (#14144).