From 3f4b2ca4dd09977ff585cfc8f52abdd8eb99e39e Mon Sep 17 00:00:00 2001 From: Felix Viernickel Date: Thu, 6 Feb 2020 18:43:03 +0100 Subject: [PATCH 1/4] Add example code to make the test-suite fail When adding a related resource to an inherited polymorphic model, that is absent on the base model, the related resource type is incorrectly resolved in get_related_resource_type. Introduce a LabResults model to the example code and add it as a related resource on the ResearchProjectSerializer to provoke an error. This already causes the test-suite to fail, so no new test has been added. --- example/models.py | 7 +++++++ example/serializers.py | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/example/models.py b/example/models.py index 601e0788..4df4dc27 100644 --- a/example/models.py +++ b/example/models.py @@ -151,6 +151,13 @@ class ResearchProject(Project): supervisor = models.CharField(max_length=30) +class LabResults(models.Model): + research_project = models.ForeignKey( + ResearchProject, related_name='lab_results', on_delete=models.CASCADE) + date = models.DateField() + measurements = models.TextField() + + class Company(models.Model): name = models.CharField(max_length=100) current_project = models.ForeignKey( diff --git a/example/serializers.py b/example/serializers.py index 9ed60e90..cc24efb0 100644 --- a/example/serializers.py +++ b/example/serializers.py @@ -15,6 +15,7 @@ Comment, Company, Entry, + LabResults, Project, ProjectType, ResearchProject, @@ -303,11 +304,20 @@ class Meta: class ResearchProjectSerializer(BaseProjectSerializer): + # testing exclusive related field on inherited polymorphic model + lab_results = relations.ResourceRelatedField(many=True, read_only=True) + class Meta: model = ResearchProject exclude = ('polymorphic_ctype',) +class LabResultsSerializer(serializers.ModelSerializer): + class Meta: + model = LabResults + fields = ('date', 'measurements') + + class ProjectSerializer(serializers.PolymorphicModelSerializer): included_serializers = { 'project_type': ProjectTypeSerializer, From 1156e20d915746885b08572cd01232138788305f Mon Sep 17 00:00:00 2001 From: Felix Viernickel Date: Thu, 6 Feb 2020 18:46:14 +0100 Subject: [PATCH 2/4] Get correct related type for polymorphic models In get_related_resource_type, check if the parent_serializer is polymorphic. If so, resolve the parent_model using the parent serializer's instance to correctly handle related resources on polymorphic models. --- rest_framework_json_api/utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py index 90b9116b..b3932651 100644 --- a/rest_framework_json_api/utils.py +++ b/rest_framework_json_api/utils.py @@ -143,6 +143,7 @@ def format_resource_type(value, format_type=None, pluralize=None): def get_related_resource_type(relation): + from rest_framework_json_api.serializers import PolymorphicModelSerializer try: return get_resource_type_from_serializer(relation) except AttributeError: @@ -165,7 +166,10 @@ def get_related_resource_type(relation): else: parent_serializer = relation.parent parent_model = None - if hasattr(parent_serializer, 'Meta'): + if isinstance(parent_serializer, PolymorphicModelSerializer): + parent_model = parent_serializer.get_polymorphic_serializer_for_instance( + parent_serializer.instance).Meta.model + elif hasattr(parent_serializer, 'Meta'): parent_model = getattr(parent_serializer.Meta, 'model', None) elif hasattr(parent_serializer, 'parent') and hasattr(parent_serializer.parent, 'Meta'): parent_model = getattr(parent_serializer.parent.Meta, 'model', None) From bd3ed362ac155449ebbae1684830fd73faee4d8d Mon Sep 17 00:00:00 2001 From: Felix Viernickel Date: Thu, 6 Feb 2020 19:09:13 +0100 Subject: [PATCH 3/4] Update AUTHORS and CHANGELOG.md --- AUTHORS | 1 + CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 1619377a..8ecb85d2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -27,3 +27,4 @@ Stas S. Nathanael Gordon Charlie Allatson Joseba Mendivil +Felix Viernickel diff --git a/CHANGELOG.md b/CHANGELOG.md index 1318b9ba..7b2b34f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ any parts of the framework not mentioned in the documentation should generally b * Ensure that `409 Conflict` is returned when processing a `PATCH` request in which the resource object’s type and id do not match the server’s endpoint properly as outlined in [JSON:API](https://jsonapi.org/format/#crud-updating-responses-409) spec. * Properly return parser error when primary data is of invalid type * Pass instance to child serializer when `PolymorphicModelSerializer` inits it in `to_internal_value` +* Handle serialization of related resources on inherited polymorphic models that are absent on the base model ## [3.0.0] - 2019-10-14 From 80121b02f66dd447dee7674286652715e0ca1675 Mon Sep 17 00:00:00 2001 From: Felix Viernickel Date: Thu, 6 Feb 2020 20:59:39 +0100 Subject: [PATCH 4/4] Add missing migration for LabResults --- example/migrations/0008_labresults.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 example/migrations/0008_labresults.py diff --git a/example/migrations/0008_labresults.py b/example/migrations/0008_labresults.py new file mode 100644 index 00000000..89323d77 --- /dev/null +++ b/example/migrations/0008_labresults.py @@ -0,0 +1,23 @@ +# Generated by Django 3.0.3 on 2020-02-06 10:24 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('example', '0007_artproject_description'), + ] + + operations = [ + migrations.CreateModel( + name='LabResults', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField()), + ('measurements', models.TextField()), + ('research_project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lab_results', to='example.ResearchProject')), + ], + ), + ]