From aad47fe1bfc789f4b0ad0dc6373c945663e91f93 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Sun, 19 Apr 2026 01:49:19 -0400 Subject: [PATCH 1/2] Refs #36986 -- Replaced yaml's Serializer._value_from_field() time handling with a representer. --- django/core/serializers/pyyaml.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/django/core/serializers/pyyaml.py b/django/core/serializers/pyyaml.py index 935d3cec493c..02e56bdd52f9 100644 --- a/django/core/serializers/pyyaml.py +++ b/django/core/serializers/pyyaml.py @@ -23,17 +23,27 @@ class DjangoSafeDumper(SafeDumper): + # The "safe" serializer is used for better interoperability. + def represent_decimal(self, data): return self.represent_scalar("tag:yaml.org,2002:str", str(data)) def represent_ordered_dict(self, data): return self.represent_mapping("tag:yaml.org,2002:map", data.items()) + def represent_time(self, data): + # Base YAML doesn't support serialization of time types (as opposed to + # dates or datetimes, which it does support). Converting them to + # strings isn't perfect, but it's better than a "!!python/time" type + # which would prevent deserialization under any other language. + return self.represent_scalar("tag:yaml.org,2002:str", str(data)) + DjangoSafeDumper.add_representer(decimal.Decimal, DjangoSafeDumper.represent_decimal) DjangoSafeDumper.add_representer( collections.OrderedDict, DjangoSafeDumper.represent_ordered_dict ) +DjangoSafeDumper.add_representer(datetime.time, DjangoSafeDumper.represent_time) class Serializer(PythonSerializer): @@ -41,19 +51,6 @@ class Serializer(PythonSerializer): internal_use_only = False - def _value_from_field(self, obj, field): - # A nasty special case: base YAML doesn't support serialization of time - # types (as opposed to dates or datetimes, which it does support). - # Since we want to use the "safe" serializer for better - # interoperability, we need to do something with those pesky times. - # Converting 'em to strings isn't perfect, but it's better than a - # "!!python/time" type which would halt deserialization under any other - # language. - value = super()._value_from_field(obj, field) - if isinstance(value, datetime.time): - value = str(value) - return value - def end_serialization(self): self.options.setdefault("allow_unicode", True) yaml.dump( From 179aa21b6dfeb9a0560a8c2bbfcf056301fc619f Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Sun, 19 Apr 2026 02:04:22 -0400 Subject: [PATCH 2/2] Fixed #37024 -- Made SITE_ID system check validation use Site._meta.pk. --- django/contrib/sites/checks.py | 32 ++++++++++++++++++++++++-------- docs/ref/checks.txt | 3 ++- tests/sites_tests/tests.py | 17 +++++++++++++++-- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/django/contrib/sites/checks.py b/django/contrib/sites/checks.py index 66e8551bed02..bf7c9b7dce3c 100644 --- a/django/contrib/sites/checks.py +++ b/django/contrib/sites/checks.py @@ -1,14 +1,30 @@ -from types import NoneType - from django.conf import settings from django.core.checks import Error +from django.core.exceptions import ValidationError def check_site_id(app_configs, **kwargs): - if hasattr(settings, "SITE_ID") and not isinstance( - settings.SITE_ID, (NoneType, int) - ): - return [ - Error("The SITE_ID setting must be an integer", id="sites.E101"), - ] + # Inner import avoids AppRegistryNotReady + from django.contrib.sites.models import Site + + if hasattr(settings, "SITE_ID"): + try: + site_id = Site._meta.pk.to_python(settings.SITE_ID) + except ValidationError as exc: + return [ + Error( + f"The SITE_ID setting failed to validate: {exc}.", id="sites.E101" + ), + ] + else: + # to_python() might coerce a SITE_ID of the wrong type to the valid + # type, e.g. "1" to 1 for AutoField. + if site_id != settings.SITE_ID: + expected_type = type(site_id).__name__ + return [ + Error( + f"The SITE_ID setting must be of type {expected_type}.", + id="sites.E101", + ), + ] return [] diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index 16f0c5dac474..fb9187c2ac9e 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -967,7 +967,8 @@ The following checks are performed on any model using a The following checks verify that :mod:`django.contrib.sites` is correctly configured: -* **sites.E101**: The :setting:`SITE_ID` setting must be an integer. +* **sites.E101**: The :setting:`SITE_ID` setting must be of type ````. + *or* The :setting:`SITE_ID` setting failed to validate: ````. ``staticfiles`` --------------- diff --git a/tests/sites_tests/tests.py b/tests/sites_tests/tests.py index 79183f7acaac..32bc8f65f9cb 100644 --- a/tests/sites_tests/tests.py +++ b/tests/sites_tests/tests.py @@ -204,12 +204,25 @@ def test_site_natural_key(self): self.assertEqual(self.site.natural_key(), (self.site.domain,)) @override_settings(SITE_ID="1") - def test_check_site_id(self): + def test_check_site_id_incorrect_type(self): self.assertEqual( check_site_id(None), [ checks.Error( - msg="The SITE_ID setting must be an integer", + msg="The SITE_ID setting must be of type int.", + id="sites.E101", + ), + ], + ) + + @override_settings(SITE_ID="x") + def test_check_site_id_failed_to_validate(self): + self.assertEqual( + check_site_id(None), + [ + checks.Error( + msg="The SITE_ID setting failed to validate: ['“x” value " + "must be an integer.'].", id="sites.E101", ), ],