From b9aa3239ab1328c915684d89b87a49459cabd30b Mon Sep 17 00:00:00 2001 From: Adam Zapletal 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),