From b9aa3239ab1328c915684d89b87a49459cabd30b Mon Sep 17 00:00:00 2001
From: Adam Zapletal <adamzap@gmail.com>
Date: Sat, 9 Nov 2024 21:20:22 -0600
Subject: [PATCH] Refs #21286 -- Fixed YAML serialization of TimeField primary
 key.

Handling for PyYAML not being able to serialize `datetime.time`
values is moved from `handle_field` to `_value_from_field` as only
non-primary key, non-relation fields are passed into `handle_field`.
---
 django/core/serializers/pyyaml.py | 12 ++++++------
 tests/serializers/models/data.py  |  5 +++--
 tests/serializers/test_data.py    |  3 ++-
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/django/core/serializers/pyyaml.py b/django/core/serializers/pyyaml.py
index ed6e4b3895..c72d1fa03b 100644
--- a/django/core/serializers/pyyaml.py
+++ b/django/core/serializers/pyyaml.py
@@ -5,6 +5,7 @@ Requires PyYaml (https://pyyaml.org/), but that's checked for in __init__.
 """
 
 import collections
+import datetime
 import decimal
 
 import yaml
@@ -12,7 +13,6 @@ import yaml
 from django.core.serializers.base import DeserializationError
 from django.core.serializers.python import Deserializer as PythonDeserializer
 from django.core.serializers.python import Serializer as PythonSerializer
-from django.db import models
 
 # Use the C (faster) implementation if possible
 try:
@@ -44,17 +44,17 @@ class Serializer(PythonSerializer):
 
     internal_use_only = False
 
-    def handle_field(self, obj, field):
+    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.
-        if isinstance(field, models.TimeField) and getattr(obj, field.name) is not None:
-            self._current[field.name] = str(getattr(obj, field.name))
-        else:
-            super().handle_field(obj, field)
+        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)
diff --git a/tests/serializers/models/data.py b/tests/serializers/models/data.py
index 212ea0e06f..bb76bfba48 100644
--- a/tests/serializers/models/data.py
+++ b/tests/serializers/models/data.py
@@ -245,8 +245,9 @@ class SmallPKData(models.Model):
 # class TextPKData(models.Model):
 #     data = models.TextField(primary_key=True)
 
-# class TimePKData(models.Model):
-#    data = models.TimeField(primary_key=True)
+
+class TimePKData(models.Model):
+    data = models.TimeField(primary_key=True)
 
 
 class UUIDData(models.Model):
diff --git a/tests/serializers/test_data.py b/tests/serializers/test_data.py
index 33ea3458de..1f8f38ba0f 100644
--- a/tests/serializers/test_data.py
+++ b/tests/serializers/test_data.py
@@ -69,6 +69,7 @@ from .models import (
     Tag,
     TextData,
     TimeData,
+    TimePKData,
     UniqueAnchor,
     UUIDData,
     UUIDDefaultData,
@@ -390,7 +391,7 @@ The end.""",
     # It contains line breaks.
     # Several of them.
     # The end."""),
-    # (pk_obj, 770, TimePKData, datetime.time(10, 42, 37)),
+    (pk_obj, 770, TimePKData, datetime.time(10, 42, 37)),
     (pk_obj, 791, UUIDData, uuid_obj),
     (fk_obj, 792, FKToUUID, uuid_obj),
     (pk_obj, 793, UUIDDefaultData, uuid_obj),