summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorYoungkwang Yang <me@youngkwang.dev>2025-12-18 13:49:13 +0900
committerJacob Walls <jacobtylerwalls@gmail.com>2025-12-22 14:21:01 -0500
commit95394443bff2cd6c5cb47c752422fe1f391bb43d (patch)
tree9569a6075cf7152be47c5163c952fb76c8ce58ac /tests
parent6ee8e9d56c17eb0014e73189950a9e8de2a8ec0e (diff)
Fixed #36786 -- Fixed XML serialization of None values in natural keys.
None values in natural keys were incorrectly serialized as the string "None", causing deserialization to fail for fields like UUIDField.
Diffstat (limited to 'tests')
-rw-r--r--tests/serializers/models/natural.py28
-rw-r--r--tests/serializers/test_natural.py66
2 files changed, 94 insertions, 0 deletions
diff --git a/tests/serializers/models/natural.py b/tests/serializers/models/natural.py
index f32d781a76..3b01385e8f 100644
--- a/tests/serializers/models/natural.py
+++ b/tests/serializers/models/natural.py
@@ -91,3 +91,31 @@ class PostToOptOutSubclassUser(models.Model):
subscribers = models.ManyToManyField(
SubclassNaturalKeyOptOutUser, related_name="subscribed_posts", blank=True
)
+
+
+class NaturalKeyWithNullableFieldManager(models.Manager):
+ def get_by_natural_key(self, name, optional_id):
+ return self.get(name=name, optional_id=optional_id)
+
+
+class NaturalKeyWithNullableField(models.Model):
+ name = models.CharField(max_length=100)
+ optional_id = models.CharField(max_length=100, null=True, blank=True)
+
+ objects = NaturalKeyWithNullableFieldManager()
+
+ class Meta:
+ unique_together = [["name", "optional_id"]]
+
+ def natural_key(self):
+ return (self.name, self.optional_id)
+
+
+class FKToNaturalKeyWithNullable(models.Model):
+ ref = models.ForeignKey(
+ NaturalKeyWithNullableField, on_delete=models.CASCADE, null=True
+ )
+ refs = models.ManyToManyField(
+ NaturalKeyWithNullableField, related_name="m2m_referrers"
+ )
+ data = models.CharField(max_length=100, default="")
diff --git a/tests/serializers/test_natural.py b/tests/serializers/test_natural.py
index 322abeb7fc..e5592f97c8 100644
--- a/tests/serializers/test_natural.py
+++ b/tests/serializers/test_natural.py
@@ -6,8 +6,10 @@ from .models import (
Child,
FKAsPKNoNaturalKey,
FKDataNaturalKey,
+ FKToNaturalKeyWithNullable,
NaturalKeyAnchor,
NaturalKeyThing,
+ NaturalKeyWithNullableField,
NaturalPKWithDefault,
PostToOptOutSubclassUser,
SubclassNaturalKeyOptOutUser,
@@ -280,6 +282,60 @@ def natural_key_opt_out_test(self, format):
)
+def nullable_natural_key_fk_test(self, format):
+ target_with_none = NaturalKeyWithNullableField.objects.create(
+ name="test_none",
+ optional_id=None,
+ )
+ target_with_value = NaturalKeyWithNullableField.objects.create(
+ name="test_value",
+ optional_id="some_id",
+ )
+ fk_to_none = FKToNaturalKeyWithNullable.objects.create(
+ ref=target_with_none,
+ data="points_to_none",
+ )
+ fk_to_value = FKToNaturalKeyWithNullable.objects.create(
+ ref=target_with_value,
+ data="points_to_value",
+ )
+ objects = [target_with_none, target_with_value, fk_to_none, fk_to_value]
+ serialized = serializers.serialize(
+ format,
+ objects,
+ use_natural_foreign_keys=True,
+ use_natural_primary_keys=True,
+ )
+ objs = list(serializers.deserialize(format, serialized))
+ self.assertEqual(objs[2].object.ref_id, target_with_none.pk)
+ self.assertEqual(objs[3].object.ref_id, target_with_value.pk)
+
+
+def nullable_natural_key_m2m_test(self, format):
+ target_with_none = NaturalKeyWithNullableField.objects.create(
+ name="test_none",
+ optional_id=None,
+ )
+ target_with_value = NaturalKeyWithNullableField.objects.create(
+ name="test_value",
+ optional_id="some_id",
+ )
+ m2m_obj = FKToNaturalKeyWithNullable.objects.create(data="m2m_test")
+ m2m_obj.refs.set([target_with_none, target_with_value])
+ objects = [target_with_none, target_with_value, m2m_obj]
+ serialized = serializers.serialize(
+ format,
+ objects,
+ use_natural_foreign_keys=True,
+ use_natural_primary_keys=True,
+ )
+ objs = list(serializers.deserialize(format, serialized))
+ self.assertCountEqual(
+ objs[2].m2m_data["refs"],
+ [target_with_none.pk, target_with_value.pk],
+ )
+
+
# Dynamically register tests for each serializer
register_tests(
NaturalKeySerializerTests,
@@ -319,3 +375,13 @@ register_tests(
"test_%s_natural_key_opt_out",
natural_key_opt_out_test,
)
+register_tests(
+ NaturalKeySerializerTests,
+ "test_%s_nullable_natural_key_fk",
+ nullable_natural_key_fk_test,
+)
+register_tests(
+ NaturalKeySerializerTests,
+ "test_%s_nullable_natural_key_m2m",
+ nullable_natural_key_m2m_test,
+)