Skip to content

Add HyperlinkedRelatedField and SerializerMethodHyperlinkedRelatedField fields #445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 19, 2018
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Adam Wróbel <https://adamwrobel.com>
Adam Ziolkowski <[email protected]>
Alan Crosswell <[email protected]>
Anton Shutik <[email protected]>
Christian Zosel <https://zosel.ch>
Greg Aker <[email protected]>
Jamie Bliss <[email protected]>
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

* Add testing configuration to `REST_FRAMEWORK` configuration as described in [DRF](http://www.django-rest-framework.org/api-guide/testing/#configuration)
* Add sorting configuration to `REST_FRAMEWORK` as defined in [json api spec](http://jsonapi.org/format/#fetching-sorting)
* Add `HyperlinkedRelatedField` and `SerializerMethodHyperlinkedRelatedField`. See [usage docs](docs/usage.md#related-fields)


v2.5.0 - Released July 11, 2018
Expand Down
8 changes: 8 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ When set to pluralize:

### Related fields

#### ResourceRelatedField

Because of the additional structure needed to represent relationships in JSON
API, this package provides the `ResourceRelatedField` for serializers, which
works similarly to `PrimaryKeyRelatedField`. By default,
Expand Down Expand Up @@ -435,6 +437,12 @@ class LineItemViewSet(viewsets.ModelViewSet):
return queryset
```

#### HyperlinkedRelatedField

`HyperlinkedRelatedField` has same functionality as `ResourceRelatedField` but does
not render `data`. Use this in case you only need links of relationships and want to lower payload
and increase performance.

### RelationshipView
`rest_framework_json_api.views.RelationshipView` is used to build
relationship views (see the
Expand Down
46 changes: 43 additions & 3 deletions example/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,58 @@ def __init__(self, *args, **kwargs):
}

body_format = serializers.SerializerMethodField()
# single related from model
blog_hyperlinked = relations.HyperlinkedRelatedField(
related_link_view_name='entry-blog',
related_link_url_kwarg='entry_pk',
self_link_view_name='entry-relationships',
read_only=True,
source='blog'
)
# many related from model
comments = relations.ResourceRelatedField(
many=True, read_only=True)
# many related hyperlinked from model
comments_hyperlinked = relations.HyperlinkedRelatedField(
related_link_view_name='entry-comments',
related_link_url_kwarg='entry_pk',
self_link_view_name='entry-relationships',
many=True,
read_only=True,
source='comments'
)
# many related from serializer
suggested = relations.SerializerMethodResourceRelatedField(
source='get_suggested', model=Entry, many=True, read_only=True,
related_link_view_name='entry-suggested',
related_link_url_kwarg='entry_pk',
self_link_view_name='entry-relationships',
source='get_suggested',
model=Entry,
many=True,
read_only=True
)
# many related hyperlinked from serializer
suggested_hyperlinked = relations.SerializerMethodHyperlinkedRelatedField(
related_link_view_name='entry-suggested',
related_link_url_kwarg='entry_pk',
self_link_view_name='entry-relationships',
source='get_suggested',
model=Entry,
many=True,
read_only=True
)
# single related from serializer
featured = relations.SerializerMethodResourceRelatedField(
source='get_featured', model=Entry, read_only=True)
# single related hyperlinked from serializer
featured_hyperlinked = relations.SerializerMethodHyperlinkedRelatedField(
related_link_view_name='entry-featured',
related_link_url_kwarg='entry_pk',
self_link_view_name='entry-relationships',
source='get_featured',
model=Entry,
read_only=True
)
tags = TaggedItemSerializer(many=True, read_only=True)

def get_suggested(self, obj):
Expand All @@ -93,8 +132,9 @@ def get_body_format(self, obj):

class Meta:
model = Entry
fields = ('blog', 'headline', 'body_text', 'pub_date', 'mod_date',
'authors', 'comments', 'featured', 'suggested', 'tags')
fields = ('blog', 'blog_hyperlinked', 'headline', 'body_text', 'pub_date', 'mod_date',
'authors', 'comments', 'comments_hyperlinked', 'featured', 'suggested',
'suggested_hyperlinked', 'tags', 'featured_hyperlinked')
read_only_fields = ('tags',)
meta_fields = ('body_format',)

Expand Down
50 changes: 50 additions & 0 deletions example/tests/integration/test_non_paginated_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
"blog": {
"data": {"type": "blogs", "id": "1"}
},
"blogHyperlinked": {
"links": {
"related": "http://testserver/entries/1/blog",
"self": "http://testserver/entries/1/relationships/blog_hyperlinked"
}
},
"authors": {
"meta": {"count": 1},
"data": [{"type": "authors", "id": "1"}]
Expand All @@ -43,13 +49,32 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
"meta": {"count": 1},
"data": [{"type": "comments", "id": "1"}]
},
"commentsHyperlinked": {
"links": {
"related": "http://testserver/entries/1/comments",
"self": "http://testserver/entries/1/relationships/comments_hyperlinked"
}
},
"suggested": {
"data": [{"type": "entries", "id": "2"}],
"links": {
"related": "http://testserver/entries/1/suggested/",
"self": "http://testserver/entries/1/relationships/suggested"
}
},
"suggestedHyperlinked": {
"links": {
"related": "http://testserver/entries/1/suggested/",
"self": "http://testserver/entries/1"
"/relationships/suggested_hyperlinked"
}
},
"featuredHyperlinked": {
"links": {
"related": "http://testserver/entries/1/featured",
"self": "http://testserver/entries/1/relationships/featured_hyperlinked"
}
},
"tags": {
"data": []
}
Expand All @@ -73,6 +98,12 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
"blog": {
"data": {"type": "blogs", "id": "2"}
},
"blogHyperlinked": {
"links": {
"related": "http://testserver/entries/2/blog",
"self": "http://testserver/entries/2/relationships/blog_hyperlinked",
}
},
"authors": {
"meta": {"count": 1},
"data": [{"type": "authors", "id": "2"}]
Expand All @@ -81,13 +112,32 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
"meta": {"count": 1},
"data": [{"type": "comments", "id": "2"}]
},
"commentsHyperlinked": {
"links": {
"related": "http://testserver/entries/2/comments",
"self": "http://testserver/entries/2/relationships/comments_hyperlinked"
}
},
"suggested": {
"data": [{"type": "entries", "id": "1"}],
"links": {
"related": "http://testserver/entries/2/suggested/",
"self": "http://testserver/entries/2/relationships/suggested"
}
},
"suggestedHyperlinked": {
"links": {
"related": "http://testserver/entries/2/suggested/",
"self": "http://testserver/entries/2"
"/relationships/suggested_hyperlinked"
}
},
"featuredHyperlinked": {
"links": {
"related": "http://testserver/entries/2/featured",
"self": "http://testserver/entries/2/relationships/featured_hyperlinked"
}
},
"tags": {
"data": []
}
Expand Down
25 changes: 25 additions & 0 deletions example/tests/integration/test_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ def test_pagination_with_single_entry(single_entry, client):
"blog": {
"data": {"type": "blogs", "id": "1"}
},
"blogHyperlinked": {
"links": {
"related": "http://testserver/entries/1/blog",
"self": "http://testserver/entries/1/relationships/blog_hyperlinked",
}
},
"authors": {
"meta": {"count": 1},
"data": [{"type": "authors", "id": "1"}]
Expand All @@ -44,13 +50,32 @@ def test_pagination_with_single_entry(single_entry, client):
"meta": {"count": 1},
"data": [{"type": "comments", "id": "1"}]
},
"commentsHyperlinked": {
"links": {
"related": "http://testserver/entries/1/comments",
"self": "http://testserver/entries/1/relationships/comments_hyperlinked"
}
},
"suggested": {
"data": [],
"links": {
"related": "http://testserver/entries/1/suggested/",
"self": "http://testserver/entries/1/relationships/suggested"
}
},
"suggestedHyperlinked": {
"links": {
"related": "http://testserver/entries/1/suggested/",
"self": "http://testserver/entries/1"
"/relationships/suggested_hyperlinked"
}
},
"featuredHyperlinked": {
"links": {
"related": "http://testserver/entries/1/featured",
"self": "http://testserver/entries/1/relationships/featured_hyperlinked"
}
},
"tags": {
"data": [
{
Expand Down
Loading