Переглянути джерело

Fixed #34818 -- Prevented GenericIPAddressField from mutating error messages.

Co-authored-by: Parth Verma <parth.verma@gmail.com>
Parth Verma 1 рік тому
батько
коміт
eabfa2d0e3

+ 11 - 7
django/core/validators.py

@@ -276,14 +276,18 @@ def validate_ipv4_address(value):
         ipaddress.IPv4Address(value)
     except ValueError:
         raise ValidationError(
-            _("Enter a valid IPv4 address."), code="invalid", params={"value": value}
+            _("Enter a valid %(protocol)s address."),
+            code="invalid",
+            params={"protocol": _("IPv4"), "value": value},
         )
 
 
 def validate_ipv6_address(value):
     if not is_valid_ipv6_address(value):
         raise ValidationError(
-            _("Enter a valid IPv6 address."), code="invalid", params={"value": value}
+            _("Enter a valid %(protocol)s address."),
+            code="invalid",
+            params={"protocol": _("IPv6"), "value": value},
         )
 
 
@@ -295,16 +299,16 @@ def validate_ipv46_address(value):
             validate_ipv6_address(value)
         except ValidationError:
             raise ValidationError(
-                _("Enter a valid IPv4 or IPv6 address."),
+                _("Enter a valid %(protocol)s address."),
                 code="invalid",
-                params={"value": value},
+                params={"protocol": _("IPv4 or IPv6"), "value": value},
             )
 
 
 ip_address_validator_map = {
-    "both": ([validate_ipv46_address], _("Enter a valid IPv4 or IPv6 address.")),
-    "ipv4": ([validate_ipv4_address], _("Enter a valid IPv4 address.")),
-    "ipv6": ([validate_ipv6_address], _("Enter a valid IPv6 address.")),
+    "both": [validate_ipv46_address],
+    "ipv4": [validate_ipv4_address],
+    "ipv6": [validate_ipv6_address],
 }
 
 

+ 4 - 6
django/db/models/fields/__init__.py

@@ -2201,7 +2201,7 @@ class IPAddressField(Field):
 class GenericIPAddressField(Field):
     empty_strings_allowed = False
     description = _("IP address")
-    default_error_messages = {}
+    default_error_messages = {"invalid": _("Enter a valid %(protocol)s address.")}
 
     def __init__(
         self,
@@ -2214,11 +2214,9 @@ class GenericIPAddressField(Field):
     ):
         self.unpack_ipv4 = unpack_ipv4
         self.protocol = protocol
-        (
-            self.default_validators,
-            invalid_error_message,
-        ) = validators.ip_address_validators(protocol, unpack_ipv4)
-        self.default_error_messages["invalid"] = invalid_error_message
+        self.default_validators = validators.ip_address_validators(
+            protocol, unpack_ipv4
+        )
         kwargs["max_length"] = 39
         super().__init__(verbose_name, name, *args, **kwargs)
 

+ 1 - 1
django/forms/fields.py

@@ -1288,7 +1288,7 @@ class GenericIPAddressField(CharField):
         self.unpack_ipv4 = unpack_ipv4
         self.default_validators = validators.ip_address_validators(
             protocol, unpack_ipv4
-        )[0]
+        )
         super().__init__(**kwargs)
 
     def to_python(self, value):

+ 3 - 1
django/utils/ipv6.py

@@ -26,7 +26,9 @@ def clean_ipv6_address(
     try:
         addr = ipaddress.IPv6Address(int(ipaddress.IPv6Address(ip_str)))
     except ValueError:
-        raise ValidationError(error_message, code="invalid")
+        raise ValidationError(
+            error_message, code="invalid", params={"protocol": _("IPv6")}
+        )
 
     if unpack_ipv4 and addr.ipv4_mapped:
         return str(addr.ipv4_mapped)

+ 14 - 0
tests/validation/tests.py

@@ -206,3 +206,17 @@ class GenericIPAddressFieldTests(ValidationAssertions, TestCase):
         self.assertIsNone(giptm.full_clean())
         giptm = GenericIPAddressTestModel(generic_ip=None)
         self.assertIsNone(giptm.full_clean())
+
+    def test_multiple_invalid_ip_raises_error(self):
+        giptm = GenericIPAddressTestModel(
+            v6_ip="1.2.3.4", v4_ip="::ffff:10.10.10.10", generic_ip="fsad"
+        )
+        self.assertFieldFailsValidationWithMessage(
+            giptm.full_clean, "v6_ip", ["Enter a valid IPv6 address."]
+        )
+        self.assertFieldFailsValidationWithMessage(
+            giptm.full_clean, "v4_ip", ["Enter a valid IPv4 address."]
+        )
+        self.assertFieldFailsValidationWithMessage(
+            giptm.full_clean, "generic_ip", ["Enter a valid IPv4 or IPv6 address."]
+        )