12
12
13
13
14
14
class ResourceRelatedField (PrimaryKeyRelatedField ):
15
+ _skip_polymorphic_optimization = True
15
16
self_link_view_name = None
16
17
related_link_view_name = None
17
18
related_link_lookup_field = 'pk'
@@ -21,6 +22,7 @@ class ResourceRelatedField(PrimaryKeyRelatedField):
21
22
'does_not_exist' : _ ('Invalid pk "{pk_value}" - object does not exist.' ),
22
23
'incorrect_type' : _ ('Incorrect type. Expected resource identifier object, received {data_type}.' ),
23
24
'incorrect_relation_type' : _ ('Incorrect relation type. Expected {relation_type}, received {received_type}.' ),
25
+ # 'incorrect_poly_relation_type': _('Incorrect relation type. Expected one of {relation_type}, received {received_type}.'),
24
26
'missing_type' : _ ('Invalid resource identifier object: missing \' type\' attribute' ),
25
27
'missing_id' : _ ('Invalid resource identifier object: missing \' id\' attribute' ),
26
28
'no_match' : _ ('Invalid hyperlink - No URL match.' ),
@@ -135,7 +137,8 @@ def to_internal_value(self, data):
135
137
self .fail ('missing_id' )
136
138
137
139
if data ['type' ] != expected_relation_type :
138
- self .conflict ('incorrect_relation_type' , relation_type = expected_relation_type , received_type = data ['type' ])
140
+ self .conflict ('incorrect_relation_type' , relation_type = expected_relation_type ,
141
+ received_type = data ['type' ])
139
142
140
143
return super (ResourceRelatedField , self ).to_internal_value (data ['id' ])
141
144
@@ -150,7 +153,8 @@ def to_representation(self, value):
150
153
resource_type = None
151
154
root = getattr (self .parent , 'parent' , self .parent )
152
155
field_name = self .field_name if self .field_name else self .parent .field_name
153
- if getattr (root , 'included_serializers' , None ) is not None and not self .is_polymorphic :
156
+ if getattr (root , 'included_serializers' , None ) is not None and \
157
+ self ._skip_polymorphic_optimization :
154
158
includes = get_included_serializers (root )
155
159
if field_name in includes .keys ():
156
160
resource_type = get_resource_type_from_serializer (includes [field_name ])
@@ -177,6 +181,42 @@ def get_choices(self, cutoff=None):
177
181
])
178
182
179
183
184
+ class PolymorphicResourceRelatedField (ResourceRelatedField ):
185
+
186
+ _skip_polymorphic_optimization = False
187
+ default_error_messages = dict (ResourceRelatedField .default_error_messages , ** {
188
+ 'incorrect_relation_type' : _ ('Incorrect relation type. Expected one of {relation_type}, '
189
+ 'received {received_type}.' ),
190
+ })
191
+
192
+ def __init__ (self , polymorphic_serializer , * args , ** kwargs ):
193
+ self .polymorphic_serializer = polymorphic_serializer
194
+ super (PolymorphicResourceRelatedField , self ).__init__ (* args , ** kwargs )
195
+
196
+ def to_internal_value (self , data ):
197
+ if isinstance (data , six .text_type ):
198
+ try :
199
+ data = json .loads (data )
200
+ except ValueError :
201
+ # show a useful error if they send a `pk` instead of resource object
202
+ self .fail ('incorrect_type' , data_type = type (data ).__name__ )
203
+ if not isinstance (data , dict ):
204
+ self .fail ('incorrect_type' , data_type = type (data ).__name__ )
205
+
206
+ if 'type' not in data :
207
+ self .fail ('missing_type' )
208
+
209
+ if 'id' not in data :
210
+ self .fail ('missing_id' )
211
+
212
+ expected_relation_types = get_resource_type_from_serializer (self .polymorphic_serializer )
213
+
214
+ if data ['type' ] not in expected_relation_types :
215
+ self .conflict ('incorrect_relation_type' , relation_type = ", " .join (
216
+ expected_relation_types ), received_type = data ['type' ])
217
+
218
+ return super (ResourceRelatedField , self ).to_internal_value (data ['id' ])
219
+
180
220
181
221
class SerializerMethodResourceRelatedField (ResourceRelatedField ):
182
222
"""
0 commit comments