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 b884535

Browse files
Anton-Shutiksliverc
authored andcommitted
Use REST framework serializer functionality to extract includes (#632)
1 parent 01e92be commit b884535

File tree

3 files changed

+27
-25
lines changed

3 files changed

+27
-25
lines changed

‎CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ any parts of the framework not mentioned in the documentation should generally b
1818

1919
* Allow to define `select_related` per include using [select_for_includes](https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html#performance-improvements)
2020
* Reduce number of queries to calculate includes by using `select_related` when possible
21+
* Use REST framework serializer functionality to extract includes. This adds support like using
22+
dotted notations in source attribute in `ResourceRelatedField`.
2123

2224
### Fixed
2325

‎example/tests/unit/test_renderers.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010

1111
# serializers
1212
class RelatedModelSerializer(serializers.ModelSerializer):
13+
blog = serializers.ReadOnlyField(source='entry.blog')
14+
1315
class Meta:
1416
model = Comment
15-
fields = ('id',)
17+
fields = ('id','blog')
1618

1719

1820
class DummyTestSerializer(serializers.ModelSerializer):
@@ -137,3 +139,13 @@ class EmptyRelationshipViewSet(views.ReadOnlyModelViewSet):
137139
assert 'relationships' in result['data']
138140
assert 'bio' in result['data']['relationships']
139141
assert result['data']['relationships']['bio'] == {'data': None}
142+
143+
144+
@pytest.mark.django_db
145+
def test_extract_relation_instance(comment):
146+
serializer = RelatedModelSerializer(instance=comment)
147+
148+
got = JSONRenderer.extract_relation_instance(
149+
field=serializer.fields['blog'], resource_instance=comment
150+
)
151+
assert got == comment.entry.blog

‎rest_framework_json_api/renderers.py‎

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from django.db.models import Manager
99
from django.utils import encoding, six
1010
from rest_framework import relations, renderers
11+
from rest_framework.fields import SkipField, get_attribute
12+
from rest_framework.relations import PKOnlyObject
1113
from rest_framework.serializers import BaseSerializer, ListSerializer, Serializer
1214
from rest_framework.settings import api_settings
1315

@@ -297,34 +299,20 @@ def extract_relationships(cls, fields, resource, resource_instance):
297299
return utils._format_object(data)
298300

299301
@classmethod
300-
def extract_relation_instance(cls, field_name, field, resource_instance, serializer):
302+
def extract_relation_instance(cls, field, resource_instance):
301303
"""
302304
Determines what instance represents given relation and extracts it.
303305
304-
Relation instance is determined by given field_name or source configured on
305-
field. As fallback is a serializer method called with name of field's source.
306+
Relation instance is determined exactly same way as it determined
307+
in parent serializer
306308
"""
307-
relation_instance = None
308-
309309
try:
310-
relation_instance = getattr(resource_instance, field_name)
311-
except AttributeError:
312-
try:
313-
# For ManyRelatedFields if `related_name` is not set
314-
# we need to access `foo_set` from `source`
315-
relation_instance = getattr(resource_instance, field.child_relation.source)
316-
except AttributeError:
317-
if hasattr(serializer, field.source):
318-
serializer_method = getattr(serializer, field.source)
319-
relation_instance = serializer_method(resource_instance)
320-
else:
321-
# case when source is a simple remap on resource_instance
322-
try:
323-
relation_instance = getattr(resource_instance, field.source)
324-
except AttributeError:
325-
pass
326-
327-
return relation_instance
310+
res = field.get_attribute(resource_instance)
311+
if isinstance(res, PKOnlyObject):
312+
return get_attribute(resource_instance, field.source_attrs)
313+
return res
314+
except SkipField:
315+
return None
328316

329317
@classmethod
330318
def extract_included(cls, fields, resource, resource_instance, included_resources,
@@ -363,7 +351,7 @@ def extract_included(cls, fields, resource, resource_instance, included_resource
363351
continue
364352

365353
relation_instance = cls.extract_relation_instance(
366-
field_name, field, resource_instance, current_serializer
354+
field, resource_instance
367355
)
368356
if isinstance(relation_instance, Manager):
369357
relation_instance = relation_instance.all()

0 commit comments

Comments
(0)

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