Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 3a963a3

Browse files
"Data" key optional in relationships
1 parent 79e7738 commit 3a963a3

File tree

2 files changed

+61
-18
lines changed

2 files changed

+61
-18
lines changed

‎rest_framework_json_api/relations.py‎

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
from django.core.exceptions import ImproperlyConfigured
88
from django.urls import NoReverseMatch
99
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, ManyRelatedFieldasDRFManyRelatedField
1212
from rest_framework.reverse import reverse
1313
from rest_framework.serializers import Serializer
1414

@@ -29,6 +29,21 @@
2929
]
3030

3131

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+
3247
class ResourceRelatedField(PrimaryKeyRelatedField):
3348
_skip_polymorphic_optimization = True
3449
self_link_view_name = None
@@ -49,7 +64,7 @@ class ResourceRelatedField(PrimaryKeyRelatedField):
4964
'no_match': _('Invalid hyperlink - No URL match.'),
5065
}
5166

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):
5368
if self_link_view_name is not None:
5469
self.self_link_view_name = self_link_view_name
5570
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
7489

7590
super(ResourceRelatedField, self).__init__(**kwargs)
7691

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+
77115
def use_pk_only_optimization(self):
78116
# We need the real object to determine its type...
79117
return self.get_resource_type_from_included_serializer() is not None
@@ -293,7 +331,8 @@ def __new__(cls, *args, **kwargs):
293331
return cls.many_init(*args, **kwargs)
294332
return super(ResourceRelatedField, cls).__new__(cls, *args, **kwargs)
295333

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
297336
model = kwargs.pop('model', None)
298337
if child_relation is not None:
299338
self.child_relation = child_relation
@@ -306,11 +345,13 @@ def many_init(cls, *args, **kwargs):
306345
list_kwargs = {k: kwargs.pop(k) for k in LINKS_PARAMS if k in kwargs}
307346
list_kwargs['child_relation'] = cls(*args, **kwargs)
308347
for key in kwargs.keys():
309-
if key in ('model',) + MANY_RELATION_KWARGS:
348+
if key in ('model','render_data') + MANY_RELATION_KWARGS:
310349
list_kwargs[key] = kwargs[key]
311350
return cls(**list_kwargs)
312351

313352
def get_attribute(self, instance):
353+
if not self.render_data:
354+
raise SkipField
314355
# check for a source fn defined on the serializer instead of the model
315356
if self.source and hasattr(self.parent, self.source):
316357
serializer_method = getattr(self.parent, self.source)

‎rest_framework_json_api/renderers.py‎

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,12 @@ def extract_relationships(cls, fields, resource, resource_instance):
134134
if not resolved:
135135
continue
136136

137+
relation_data = {}
137138
# special case for ResourceRelatedField
138-
relation_data = {
139-
'data': resource.get(field_name)
140-
}
139+
if field_name in resource:
140+
relation_data.update({
141+
'data': resource.get(field_name)
142+
})
141143

142144
field_links = field.get_links(
143145
resource_instance, field.related_link_lookup_field)
@@ -188,9 +190,15 @@ def extract_relationships(cls, fields, resource, resource_instance):
188190

189191
if isinstance(field.child_relation, ResourceRelatedField):
190192
# special case for ResourceRelatedField
191-
relation_data = {
192-
'data': resource.get(field_name)
193-
}
193+
relation_data = {}
194+
195+
if field_name in resource:
196+
relation_data.update({
197+
'data': resource.get(field_name),
198+
'meta': {
199+
'count': len(resource.get(field_name))
200+
}
201+
})
194202

195203
field_links = field.child_relation.get_links(
196204
resource_instance,
@@ -200,13 +208,7 @@ def extract_relationships(cls, fields, resource, resource_instance):
200208
{'links': field_links}
201209
if field_links else dict()
202210
)
203-
relation_data.update(
204-
{
205-
'meta': {
206-
'count': len(resource.get(field_name))
207-
}
208-
}
209-
)
211+
210212
data.update({field_name: relation_data})
211213
continue
212214

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /