|
3 | 3 | import pytest |
4 | 4 |
|
5 | 5 | try: |
| 6 | + from rest_framework import serializers |
6 | 7 | from rest_framework.test import APIClient |
7 | 8 |
|
8 | 9 | from polymorphic.contrib.drf.serializers import PolymorphicSerializer |
@@ -302,6 +303,71 @@ def test_get_serializer_from_resource_type_keyerror_propagation(self): |
302 | 303 | assert "resourcetype" in excinfo.value.detail |
303 | 304 | assert "Invalid resourcetype" in str(excinfo.value.detail["resourcetype"]) |
304 | 305 |
|
| 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 | + |
305 | 371 |
|
306 | 372 | class TestProjectViewSet: |
307 | 373 | """Test the example Project ViewSet with polymorphic serializers.""" |
|
0 commit comments