7
7
from django .core .exceptions import ImproperlyConfigured
8
8
from django .urls import NoReverseMatch
9
9
from django .utils .translation import ugettext_lazy as _
10
- from rest_framework .fields import MISSING_ERROR_MESSAGE
11
- from rest_framework .relations import MANY_RELATION_KWARGS , PrimaryKeyRelatedField
10
+ from rest_framework .fields import MISSING_ERROR_MESSAGE , SkipField
11
+ from rest_framework .relations import MANY_RELATION_KWARGS , PrimaryKeyRelatedField , ManyRelatedField as DRFManyRelatedField
12
12
from rest_framework .reverse import reverse
13
13
from rest_framework .serializers import Serializer
14
14
29
29
]
30
30
31
31
32
+ class ManyRelatedField (DRFManyRelatedField ):
33
+ '''
34
+ This workaround skips "data" rendering for relationships in order to save some sql queries and improve performance
35
+ '''
36
+
37
+ def __init__ (self , child_relation = None , * args , ** kwargs ):
38
+ self .render_data = kwargs .pop ('render_data' , True )
39
+ super (ManyRelatedField , self ).__init__ (child_relation , * args , ** kwargs )
40
+
41
+ def get_attribute (self , instance ):
42
+ if self .render_data :
43
+ return super (ManyRelatedField , self ).get_attribute (instance )
44
+ raise SkipField
45
+
46
+
32
47
class ResourceRelatedField (PrimaryKeyRelatedField ):
33
48
_skip_polymorphic_optimization = True
34
49
self_link_view_name = None
@@ -49,7 +64,7 @@ class ResourceRelatedField(PrimaryKeyRelatedField):
49
64
'no_match' : _ ('Invalid hyperlink - No URL match.' ),
50
65
}
51
66
52
- def __init__ (self , self_link_view_name = None , related_link_view_name = None , ** kwargs ):
67
+ def __init__ (self , self_link_view_name = None , related_link_view_name = None , render_data = True , ** kwargs ):
53
68
if self_link_view_name is not None :
54
69
self .self_link_view_name = self_link_view_name
55
70
if related_link_view_name is not None :
@@ -74,6 +89,29 @@ def __init__(self, self_link_view_name=None, related_link_view_name=None, **kwar
74
89
75
90
super (ResourceRelatedField , self ).__init__ (** kwargs )
76
91
92
+ @classmethod
93
+ def many_init (cls , * args , ** kwargs ):
94
+ """
95
+ This method handles creating a parent `ManyRelatedField` instance
96
+ when the `many=True` keyword argument is passed.
97
+
98
+ Typically you won't need to override this method.
99
+
100
+ Note that we're over-cautious in passing most arguments to both parent
101
+ and child classes in order to try to cover the general case. If you're
102
+ overriding this method you'll probably want something much simpler, eg:
103
+
104
+ @classmethod
105
+ def many_init(cls, *args, **kwargs):
106
+ kwargs['child'] = cls()
107
+ return CustomManyRelatedField(*args, **kwargs)
108
+ """
109
+ list_kwargs = {'child_relation' : cls (* args , ** kwargs )}
110
+ for key in kwargs .keys ():
111
+ if key in MANY_RELATION_KWARGS + ('render_data' ,):
112
+ list_kwargs [key ] = kwargs [key ]
113
+ return ManyRelatedField (** list_kwargs )
114
+
77
115
def use_pk_only_optimization (self ):
78
116
# We need the real object to determine its type...
79
117
return self .get_resource_type_from_included_serializer () is not None
@@ -293,7 +331,8 @@ def __new__(cls, *args, **kwargs):
293
331
return cls .many_init (* args , ** kwargs )
294
332
return super (ResourceRelatedField , cls ).__new__ (cls , * args , ** kwargs )
295
333
296
- def __init__ (self , child_relation = None , * args , ** kwargs ):
334
+ def __init__ (self , child_relation = None , render_data = True , * args , ** kwargs ):
335
+ self .render_data = render_data
297
336
model = kwargs .pop ('model' , None )
298
337
if child_relation is not None :
299
338
self .child_relation = child_relation
@@ -306,11 +345,13 @@ def many_init(cls, *args, **kwargs):
306
345
list_kwargs = {k : kwargs .pop (k ) for k in LINKS_PARAMS if k in kwargs }
307
346
list_kwargs ['child_relation' ] = cls (* args , ** kwargs )
308
347
for key in kwargs .keys ():
309
- if key in ('model' ,) + MANY_RELATION_KWARGS :
348
+ if key in ('model' , 'render_data' ) + MANY_RELATION_KWARGS :
310
349
list_kwargs [key ] = kwargs [key ]
311
350
return cls (** list_kwargs )
312
351
313
352
def get_attribute (self , instance ):
353
+ if not self .render_data :
354
+ raise SkipField
314
355
# check for a source fn defined on the serializer instead of the model
315
356
if self .source and hasattr (self .parent , self .source ):
316
357
serializer_method = getattr (self .parent , self .source )
0 commit comments