Skip to content

Commit eae1180

Browse files
committed
Working on related fields - ManyRelatedFields with HyperLinked relations are working
1 parent 19d3e8d commit eae1180

File tree

2 files changed

+52
-24
lines changed

2 files changed

+52
-24
lines changed

rest_framework_json_api/renderers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ def render(self, data, accepted_media_type=None, renderer_context=None):
6969
resource_data = [
7070
('type', resource_name),
7171
('id', utils.extract_id(fields, resource)),
72-
('attributes', utils.format_keys(utils.extract_attributes(fields, resource)))
72+
('attributes', utils.extract_attributes(fields, resource)),
73+
('relationships', utils.extract_relationships(fields, resource)),
7374
]
7475
# Add 'self' link if field is present and valid
7576
if api_settings.URL_FIELD_NAME in resource and \

rest_framework_json_api/utils.py

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@
33
"""
44
import inflection
55

6-
76
from django.core import urlresolvers
87
from django.conf import settings
98
from django.utils import six, encoding
109
from django.utils.six.moves.urllib.parse import urlparse, urlunparse
1110
from django.utils.translation import ugettext_lazy as _
1211

13-
from rest_framework.serializers import Serializer, BaseSerializer
14-
from rest_framework.relations import RelatedField
12+
from rest_framework.serializers import BaseSerializer
13+
from rest_framework.relations import RelatedField, HyperlinkedRelatedField
1514
from rest_framework.settings import api_settings
1615
from rest_framework.exceptions import APIException
1716

@@ -25,11 +24,6 @@
2524
except ImportError:
2625
ManyRelatedField = type(None)
2726

28-
try:
29-
from rest_framework.serializers import ListSerializer
30-
except ImportError:
31-
ListSerializer = type(None)
32-
3327

3428
def get_resource_name(context):
3529
"""
@@ -58,13 +52,13 @@ def get_resource_name(context):
5852
# Check the meta class
5953
resource_name = (
6054
getattr(view, 'serializer_class')
61-
.Meta.resource_name)
55+
.Meta.resource_name)
6256
except AttributeError:
6357
# Use the model
6458
try:
6559
resource_name = (
6660
getattr(view, 'serializer_class')
67-
.Meta.model.__name__)
61+
.Meta.model.__name__)
6862
except AttributeError:
6963
try:
7064
resource_name = view.model.__name__
@@ -121,28 +115,61 @@ def format_keys(obj, format_type=None):
121115
return obj
122116

123117

118+
def extract_id_from_url(url):
119+
http_prefix = url.startswith(('http:', 'https:'))
120+
if http_prefix:
121+
# If needed convert absolute URLs to relative path
122+
data = urlparse(url).path
123+
prefix = urlresolvers.get_script_prefix()
124+
if data.startswith(prefix):
125+
url = '/' + data[len(prefix):]
126+
127+
match = urlresolvers.resolve(url)
128+
return encoding.force_text(match.kwargs['pk'])
129+
130+
124131
def extract_id(fields, resource):
125132
for field_name, field in six.iteritems(fields):
126133
if field_name == 'id':
127134
return encoding.force_text(resource[field_name])
128135
if field_name == api_settings.URL_FIELD_NAME:
129-
url = resource[field_name]
130-
http_prefix = url.startswith(('http:', 'https:'))
131-
if http_prefix:
132-
# If needed convert absolute URLs to relative path
133-
data = urlparse(url).path
134-
prefix = urlresolvers.get_script_prefix()
135-
if data.startswith(prefix):
136-
url = '/' + data[len(prefix):]
137-
138-
match = urlresolvers.resolve(url)
139-
return encoding.force_text(match.kwargs['pk'])
136+
return extract_id_from_url(resource[field_name])
140137

141138

142139
def extract_attributes(fields, resource):
143140
data = OrderedDict()
144141
for field_name, field in six.iteritems(fields):
145-
if not (isinstance(field, RelatedField) or isinstance(field, BaseSerializer)):
146-
data.update({field_name: encoding.force_text(resource[field_name])})
142+
# Skip fields with relations
143+
if isinstance(field, (RelatedField, BaseSerializer, ManyRelatedField)):
144+
continue
145+
146+
data.update({field_name: encoding.force_text(resource[field_name])})
147+
148+
return format_keys(data)
149+
150+
151+
def extract_relationships(fields, resource):
152+
data = OrderedDict()
153+
for field_name, field in six.iteritems(fields):
154+
# Skip URL field
155+
if field_name == api_settings.URL_FIELD_NAME:
156+
continue
157+
158+
# Skip fields without relations
159+
if not isinstance(field, (RelatedField, BaseSerializer, ManyRelatedField)):
160+
continue
161+
162+
if isinstance(field, ManyRelatedField):
163+
relation_data = list()
164+
165+
relation = field.child_relation
166+
model = relation.queryset.model
167+
relation_type = inflection.pluralize(model.__name__).lower()
168+
169+
if isinstance(relation, HyperlinkedRelatedField):
170+
for link in resource[field_name]:
171+
relation_data.append(OrderedDict([('type', relation_type), ('id', extract_id_from_url(link))]))
172+
173+
data.update({field_name: {'data': relation_data}})
147174

148175
return format_keys(data)

0 commit comments

Comments
 (0)