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 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')), + ], + ), + ] 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, 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)