|  | 
| 1 | 1 | from datetime import datetime | 
| 2 |  | -from rest_framework_json_api import serializers, relations | 
|  | 2 | +from django.db.models.query import QuerySet | 
|  | 3 | +from rest_framework.utils.serializer_helpers import BindingDict | 
|  | 4 | +from rest_framework_json_api import serializers, relations, utils | 
| 3 | 5 | from example import models | 
| 4 | 6 | 
 | 
| 5 | 7 | 
 | 
| @@ -43,13 +45,13 @@ def __init__(self, *args, **kwargs): | 
| 43 | 45 |             source='comment_set', many=True, read_only=True) | 
| 44 | 46 |     # many related from serializer | 
| 45 | 47 |     suggested = relations.SerializerMethodResourceRelatedField( | 
| 46 |  | -            source='get_suggested', model=Entry, many=True, read_only=True) | 
|  | 48 | +            source='get_suggested', model=models.Entry, many=True, read_only=True) | 
| 47 | 49 |     # single related from serializer | 
| 48 | 50 |     featured = relations.SerializerMethodResourceRelatedField( | 
| 49 |  | -            source='get_featured', model=Entry, read_only=True) | 
|  | 51 | +            source='get_featured', model=models.Entry, read_only=True) | 
| 50 | 52 | 
 | 
| 51 | 53 |     def get_suggested(self, obj): | 
| 52 |  | -        return models.Entry.objects.exclude(pk=obj.pk).first() | 
|  | 54 | +        return models.Entry.objects.exclude(pk=obj.pk) | 
| 53 | 55 | 
 | 
| 54 | 56 |     def get_featured(self, obj): | 
| 55 | 57 |         return models.Entry.objects.exclude(pk=obj.pk).first() | 
| @@ -107,19 +109,48 @@ class Meta: | 
| 107 | 109 | 
 | 
| 108 | 110 | class ProjectSerializer(serializers.ModelSerializer): | 
| 109 | 111 | 
 | 
|  | 112 | +    polymorphic_serializers = [ | 
|  | 113 | +        {'model': models.ArtProject, 'serializer': ArtProjectSerializer}, | 
|  | 114 | +        {'model': models.ResearchProject, 'serializer': ResearchProjectSerializer}, | 
|  | 115 | +    ] | 
|  | 116 | + | 
| 110 | 117 |     class Meta: | 
| 111 | 118 |         model = models.Project | 
| 112 | 119 |         exclude = ('polymorphic_ctype',) | 
| 113 | 120 | 
 | 
|  | 121 | +    def _get_actual_serializer_from_instance(self, instance): | 
|  | 122 | +        for info in self.polymorphic_serializers: | 
|  | 123 | +            if isinstance(instance, info.get('model')): | 
|  | 124 | +                actual_serializer = info.get('serializer') | 
|  | 125 | +                return actual_serializer(instance, context=self.context) | 
|  | 126 | + | 
|  | 127 | +    @property | 
|  | 128 | +    def fields(self): | 
|  | 129 | +        _fields = BindingDict(self) | 
|  | 130 | +        for key, value in self.get_fields().items(): | 
|  | 131 | +            _fields[key] = value | 
|  | 132 | +        return _fields | 
|  | 133 | + | 
|  | 134 | +    def get_fields(self): | 
|  | 135 | +        if self.instance is not None: | 
|  | 136 | +            if not isinstance(self.instance, QuerySet): | 
|  | 137 | +                return self._get_actual_serializer_from_instance(self.instance).get_fields() | 
|  | 138 | +            else: | 
|  | 139 | +                raise Exception("Cannot get fields from a polymorphic serializer given a queryset") | 
|  | 140 | +        return super(ProjectSerializer, self).get_fields() | 
|  | 141 | + | 
| 114 | 142 |     def to_representation(self, instance): | 
| 115 | 143 |         # Handle polymorphism | 
| 116 |  | -        if isinstance(instance, models.ArtProject): | 
| 117 |  | -            return ArtProjectSerializer( | 
| 118 |  | -                instance, context=self.context).to_representation(instance) | 
| 119 |  | -        elif isinstance(instance, models.ResearchProject): | 
| 120 |  | -            return ResearchProjectSerializer( | 
| 121 |  | -                instance, context=self.context).to_representation(instance) | 
| 122 |  | -        return super(ProjectSerializer, self).to_representation(instance) | 
|  | 144 | +        return self._get_actual_serializer_from_instance(instance).to_representation(instance) | 
|  | 145 | + | 
|  | 146 | +    def to_internal_value(self, data): | 
|  | 147 | +        data_type = data.get('type') | 
|  | 148 | +        for info in self.polymorphic_serializers: | 
|  | 149 | +            actual_serializer = info['serializer'] | 
|  | 150 | +            if data_type == utils.get_resource_type_from_serializer(actual_serializer): | 
|  | 151 | +                self.__class__ = actual_serializer | 
|  | 152 | +                return actual_serializer(data, context=self.context).to_internal_value(data) | 
|  | 153 | +        raise Exception("Could not deserialize") | 
| 123 | 154 | 
 | 
| 124 | 155 | 
 | 
| 125 | 156 | class CompanySerializer(serializers.ModelSerializer): | 
|  | 
0 commit comments