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 8c2b5af

Browse files
housleyjksliverc
authored andcommitted
Allow HyperlinkedRelatedField to be used with related urls (#529)
Fixes #521
1 parent f309c7c commit 8c2b5af

File tree

7 files changed

+36
-12
lines changed

7 files changed

+36
-12
lines changed

‎AUTHORS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ santiavenda <santiavenda2@gmail.com>
2020
Tim Selman <timcbaoth@gmail.com>
2121
Yaniv Peer <yanivpeer@gmail.com>
2222
Mohammed Ali Zubair <mazg1493@gmail.com>
23+
Jason Housley <housleyjk@gmail.com>

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ any parts of the framework not mentioned in the documentation should generally b
2727
* Avoid error with related urls when retrieving relationship which is referenced as `ForeignKey` on parent
2828
* Do not render `write_only` relations
2929
* Do not skip empty one-to-one relationships
30+
* Allow `HyperlinkRelatedField` to be used with [related urls](https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html?highlight=related%20links#related-urls)
3031

3132

3233
## [2.6.0] - 2018年09月20日

‎example/models.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class Comment(BaseModel):
110110
null=True,
111111
blank=True,
112112
on_delete=models.CASCADE,
113+
related_name='comments',
113114
)
114115

115116
def __str__(self):

‎example/serializers.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,20 +219,27 @@ class AuthorSerializer(serializers.ModelSerializer):
219219
read_only=True,
220220
source='get_first_entry'
221221
)
222+
comments = relations.HyperlinkedRelatedField(
223+
related_link_view_name='author-related',
224+
self_link_view_name='author-relationships',
225+
queryset=Comment.objects,
226+
many=True
227+
)
222228
included_serializers = {
223229
'bio': AuthorBioSerializer,
224230
'type': AuthorTypeSerializer
225231
}
226232
related_serializers = {
227233
'bio': 'example.serializers.AuthorBioSerializer',
228234
'type': 'example.serializers.AuthorTypeSerializer',
235+
'comments': 'example.serializers.CommentSerializer',
229236
'entries': 'example.serializers.EntrySerializer',
230237
'first_entry': 'example.serializers.EntrySerializer'
231238
}
232239

233240
class Meta:
234241
model = Author
235-
fields = ('name', 'email', 'bio', 'entries', 'first_entry', 'type')
242+
fields = ('name', 'email', 'bio', 'entries', 'comments', 'first_entry', 'type')
236243

237244
def get_first_entry(self, obj):
238245
return obj.entries.first()

‎example/settings/test.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@
1313
JSON_API_FORMAT_TYPES = 'camelize'
1414
JSON_API_PLURALIZE_TYPES = True
1515

16-
REST_FRAMEWORK.update({
16+
REST_FRAMEWORK.update({# noqa
1717
'PAGE_SIZE': 1,
1818
})

‎example/tests/test_views.py‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,11 @@ def test_get_empty_to_one_relationship(self):
102102
assert response.data == expected_data
103103

104104
def test_get_to_many_relationship_self_link(self):
105-
url = '/authors/{}/relationships/comment_set'.format(self.author.id)
105+
url = '/authors/{}/relationships/comments'.format(self.author.id)
106106

107107
response = self.client.get(url)
108108
expected_data = {
109-
'links': {'self': 'http://testserver/authors/1/relationships/comment_set'},
109+
'links': {'self': 'http://testserver/authors/1/relationships/comments'},
110110
'data': [{'id': str(self.second_comment.id), 'type': format_resource_type('Comment')}]
111111
}
112112
assert json.loads(response.content.decode('utf-8')) == expected_data
@@ -222,7 +222,7 @@ def test_delete_one_to_many_relationship_with_not_null_constraint(self):
222222
assert response.status_code == 409, response.content.decode()
223223

224224
def test_delete_to_many_relationship_with_change(self):
225-
url = '/authors/{}/relationships/comment_set'.format(self.author.id)
225+
url = '/authors/{}/relationships/comments'.format(self.author.id)
226226
request_data = {
227227
'data': [{'type': format_resource_type('Comment'), 'id': str(self.second_comment.id)}, ]
228228
}
@@ -233,7 +233,7 @@ def test_new_comment_data_patch_to_many_relationship(self):
233233
entry = EntryFactory(blog=self.blog, authors=(self.author,))
234234
comment = CommentFactory(entry=entry)
235235

236-
url = '/authors/{}/relationships/comment_set'.format(self.author.id)
236+
url = '/authors/{}/relationships/comments'.format(self.author.id)
237237
request_data = {
238238
'data': [{'type': format_resource_type('Comment'), 'id': str(comment.id)}, ]
239239
}
@@ -244,7 +244,7 @@ def test_new_comment_data_patch_to_many_relationship(self):
244244
}
245245
],
246246
'links': {
247-
'self': 'http://testserver/authors/{}/relationships/comment_set'.format(
247+
'self': 'http://testserver/authors/{}/relationships/comments'.format(
248248
self.author.id
249249
)
250250
}
@@ -261,7 +261,7 @@ def test_new_comment_data_patch_to_many_relationship(self):
261261
}
262262
],
263263
'links': {
264-
'self': 'http://testserver/authors/{}/relationships/comment_set'.format(
264+
'self': 'http://testserver/authors/{}/relationships/comments'.format(
265265
self.author.id
266266
)
267267
}
@@ -369,6 +369,16 @@ def test_retrieve_related_many(self):
369369
self.assertEqual(len(resp.json()['data']), 1)
370370
self.assertEqual(resp.json()['data'][0]['id'], str(entry.id))
371371

372+
def test_retrieve_related_many_hyperlinked(self):
373+
comment = CommentFactory(author=self.author)
374+
url = reverse('author-related', kwargs={'pk': self.author.pk, 'related_field': 'comments'})
375+
resp = self.client.get(url)
376+
377+
self.assertEqual(resp.status_code, 200)
378+
self.assertTrue(isinstance(resp.json()['data'], list))
379+
self.assertEqual(len(resp.json()['data']), 1)
380+
self.assertEqual(resp.json()['data'][0]['id'], str(comment.id))
381+
372382
def test_retrieve_related_None(self):
373383
kwargs = {'pk': self.author.pk, 'related_field': 'first_entry'}
374384
url = reverse('author-related', kwargs=kwargs)

‎rest_framework_json_api/views.py‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from rest_framework.relations import PKOnlyObject
1919
from rest_framework.response import Response
2020
from rest_framework.reverse import reverse
21-
from rest_framework.serializers import Serializer
21+
from rest_framework.serializers import Serializer, SkipField
2222

2323
from rest_framework_json_api.exceptions import Conflict
2424
from rest_framework_json_api.serializers import ResourceIdentifierObjectSerializer
@@ -166,10 +166,14 @@ def get_related_instance(self):
166166
field = parent_serializer.fields.get(field_name, None)
167167

168168
if field is not None:
169-
instance=field.get_attribute(parent_obj)
170-
ifisinstance(instance, PKOnlyObject):
171-
# need whole object
169+
try:
170+
instance=field.get_attribute(parent_obj)
171+
exceptSkipField:
172172
instance = get_attribute(parent_obj, field.source_attrs)
173+
else:
174+
if isinstance(instance, PKOnlyObject):
175+
# need whole object
176+
instance = get_attribute(parent_obj, field.source_attrs)
173177
return instance
174178
else:
175179
try:

0 commit comments

Comments
(0)

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