Skip to content

Commit 8b2cb37

Browse files
authored
Merge pull request #841 from bckohan/drf_bug
Polymorphic serializer validated data is now updated with the child data
2 parents 2378a55 + 4f190f6 commit 8b2cb37

6 files changed

Lines changed: 79 additions & 4 deletions

File tree

docs/changelog/index.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
Changelog
22
=========
33

4-
v4.10.0 (2026-XX-XX)
4+
v4.10.1 (2026-01-13)
5+
--------------------
6+
7+
* Fixed `Django-polymorphic does not update the PolymorphicSerializer's validated_data after running the child's validation method <https://github.com/jazzband/django-polymorphic/pull/378>`_
8+
9+
v4.10.0 (2026-01-13)
510
--------------------
611

712
This release is primarily an integrations release. Many tests were added for the documented

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "django-polymorphic"
7-
version = "4.10.0"
7+
version = "4.10.1"
88
description = "Seamless polymorphic inheritance for Django models."
99
readme = "README.md"
1010
license = "BSD-3-Clause"

src/polymorphic/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
Seamless Polymorphic Inheritance for Django Models
2020
"""
2121

22-
VERSION = "4.10.0"
22+
VERSION = "4.10.1"
2323

2424
__title__ = "Django Polymorphic"
2525
__version__ = VERSION # version synonym for backwards compatibility

src/polymorphic/contrib/drf/serializers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ def is_valid(self, *args, **kwargs):
9393
child_valid = False
9494
else:
9595
child_valid = serializer.is_valid(*args, **kwargs)
96+
# Update parent's validated_data with child's validated_data
97+
# to preserve any modifications made in child's validate() method
98+
if child_valid and hasattr(self, "_validated_data"):
99+
self._validated_data.update(serializer._validated_data)
96100
self._errors.update(serializer.errors)
97101
return valid and child_valid
98102

src/polymorphic/tests/examples/integrations/drf/test.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import pytest
44

55
try:
6+
from rest_framework import serializers
67
from rest_framework.test import APIClient
78

89
from polymorphic.contrib.drf.serializers import PolymorphicSerializer
@@ -302,6 +303,71 @@ def test_get_serializer_from_resource_type_keyerror_propagation(self):
302303
assert "resourcetype" in excinfo.value.detail
303304
assert "Invalid resourcetype" in str(excinfo.value.detail["resourcetype"])
304305

306+
def test_validate_method_modifications_are_preserved(self):
307+
"""Test that modifications made in child serializer's validate() method are preserved."""
308+
# Track whether the extra_field was present during create
309+
created_with_extra_field = []
310+
311+
# Create a custom serializer that adds a field in validate()
312+
class CustomBlogOneSerializer(BlogOneSerializer):
313+
extra_field = serializers.CharField(required=False, allow_null=True)
314+
315+
class Meta(BlogOneSerializer.Meta):
316+
fields = BlogOneSerializer.Meta.fields + ("extra_field",)
317+
318+
def validate(self, attrs):
319+
attrs = super().validate(attrs)
320+
# Simulate adding data in validate(), like adding the current user
321+
attrs["extra_field"] = "added_in_validate"
322+
return attrs
323+
324+
def create(self, validated_data):
325+
# Record whether extra_field was in validated_data
326+
created_with_extra_field.append("extra_field" in validated_data)
327+
# Remove extra_field before creating the model instance
328+
validated_data.pop("extra_field", None)
329+
return super().create(validated_data)
330+
331+
class CustomBlogPolymorphicSerializer(PolymorphicSerializer):
332+
model_serializer_mapping = {
333+
BlogBase: BlogBaseSerializer,
334+
BlogOne: CustomBlogOneSerializer,
335+
}
336+
337+
# Create data without the extra_field
338+
data = {
339+
"name": "test",
340+
"slug": "test-slug",
341+
"info": "test-info",
342+
"resourcetype": "BlogOne",
343+
}
344+
345+
serializer = CustomBlogPolymorphicSerializer(data=data)
346+
assert serializer.is_valid(), f"Validation errors: {serializer.errors}"
347+
348+
# Verify that the extra_field added in validate() is in validated_data
349+
assert "extra_field" in serializer.validated_data
350+
assert serializer.validated_data["extra_field"] == "added_in_validate"
351+
352+
# Verify that resource_type field is still preserved in parent's validated_data
353+
assert "resourcetype" in serializer.validated_data
354+
assert serializer.validated_data["resourcetype"] == "BlogOne"
355+
356+
# Save and verify that the field was present during create
357+
# Note: This would fail before the fix because the parent's _validated_data
358+
# wasn't updated with the child's _validated_data after calling child.is_valid()
359+
instance = serializer.save()
360+
361+
# Verify that extra_field was indeed present when create() was called
362+
assert created_with_extra_field == [True], (
363+
"extra_field should have been in validated_data when create() was called"
364+
)
365+
366+
# Verify the instance was created successfully
367+
assert instance.name == "test"
368+
assert instance.slug == "test-slug"
369+
assert instance.info == "test-info"
370+
305371

306372
class TestProjectViewSet:
307373
"""Test the example Project ViewSet with polymorphic serializers."""

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)