diff --git a/example/serializers.py b/example/serializers.py index 7929577b..e20a7c5f 100644 --- a/example/serializers.py +++ b/example/serializers.py @@ -44,7 +44,11 @@ def __init__(self, *args, **kwargs): source='comment_set', many=True, read_only=True) # many related from serializer suggested = relations.SerializerMethodResourceRelatedField( - source='get_suggested', model=Entry, many=True, read_only=True) + 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', + ) # single related from serializer featured = relations.SerializerMethodResourceRelatedField( source='get_featured', model=Entry, read_only=True) diff --git a/example/tests/integration/test_non_paginated_responses.py b/example/tests/integration/test_non_paginated_responses.py index de9e3055..d0a9adb0 100644 --- a/example/tests/integration/test_non_paginated_responses.py +++ b/example/tests/integration/test_non_paginated_responses.py @@ -43,7 +43,11 @@ def test_multiple_entries_no_pagination(multiple_entries, rf): "data": [{"type": "comments", "id": "1"}] }, "suggested": { - "data": [{"type": "entries", "id": "2"}] + "data": [{"type": "entries", "id": "2"}], + "links": { + "related": "http://testserver/entries/1/suggested/", + "self": "http://testserver/entries/1/relationships/suggested" + } } } }, @@ -74,7 +78,11 @@ def test_multiple_entries_no_pagination(multiple_entries, rf): "data": [{"type": "comments", "id": "2"}] }, "suggested": { - "data": [{"type": "entries", "id": "1"}] + "data": [{"type": "entries", "id": "1"}], + "links": { + "related": "http://testserver/entries/2/suggested/", + "self": "http://testserver/entries/2/relationships/suggested" + } } } }, diff --git a/example/tests/integration/test_pagination.py b/example/tests/integration/test_pagination.py index 742be523..482ac460 100644 --- a/example/tests/integration/test_pagination.py +++ b/example/tests/integration/test_pagination.py @@ -37,7 +37,11 @@ def test_pagination_with_single_entry(single_entry, client): "data": [{"type": "comments", "id": "1"}] }, "suggested": { - "data": [] + "data": [], + "links": { + "related": "http://testserver/entries/1/suggested/", + "self": "http://testserver/entries/1/relationships/suggested" + } } } }], diff --git a/example/urls_test.py b/example/urls_test.py index 0f8ed73b..2804863d 100644 --- a/example/urls_test.py +++ b/example/urls_test.py @@ -23,6 +23,10 @@ GenericIdentity.as_view(), name='user-default'), + url(r'^entries/(?P[^/.]+)/suggested/', + EntryViewSet.as_view({'get': 'list'}), + name='entry-suggested' + ), url(r'^entries/(?P[^/.]+)/relationships/(?P\w+)', EntryRelationshipView.as_view(), name='entry-relationships'), diff --git a/rest_framework_json_api/relations.py b/rest_framework_json_api/relations.py index 9762bc74..b4eefc45 100644 --- a/rest_framework_json_api/relations.py +++ b/rest_framework_json_api/relations.py @@ -1,6 +1,7 @@ +import collections import json -from rest_framework.fields import MISSING_ERROR_MESSAGE +from rest_framework.fields import MISSING_ERROR_MESSAGE, SerializerMethodField from rest_framework.relations import * from django.utils.translation import ugettext_lazy as _ from django.db.models.query import QuerySet @@ -10,6 +11,8 @@ get_resource_type_from_queryset, get_resource_type_from_instance, \ get_included_serializers, get_resource_type_from_serializer +LINKS_PARAMS = ['self_link_view_name', 'related_link_view_name', 'related_link_lookup_field', 'related_link_url_kwarg'] + class ResourceRelatedField(PrimaryKeyRelatedField): self_link_view_name = None @@ -171,7 +174,6 @@ def get_choices(self, cutoff=None): ]) - class SerializerMethodResourceRelatedField(ResourceRelatedField): """ Allows us to use serializer method RelatedFields @@ -190,17 +192,20 @@ def __init__(self, child_relation=None, *args, **kwargs): # DRF 3.1 doesn't expect the `many` kwarg kwargs.pop('many', None) model = kwargs.pop('model', None) + if child_relation is not None: + self.child_relation = child_relation if model: self.model = model - super(SerializerMethodResourceRelatedField, self).__init__(child_relation, *args, **kwargs) + super(SerializerMethodResourceRelatedField, self).__init__(*args, **kwargs) @classmethod def many_init(cls, *args, **kwargs): - list_kwargs = {'child_relation': cls(*args, **kwargs)} + list_kwargs = {k: kwargs.pop(k) for k in LINKS_PARAMS if k in kwargs} + list_kwargs['child_relation'] = cls(*args, **kwargs) for key in kwargs.keys(): if key in ('model',) + MANY_RELATION_KWARGS: list_kwargs[key] = kwargs[key] - return SerializerMethodResourceRelatedField(**list_kwargs) + return cls(**list_kwargs) def get_attribute(self, instance): # check for a source fn defined on the serializer instead of the model @@ -211,10 +216,7 @@ def get_attribute(self, instance): return super(SerializerMethodResourceRelatedField, self).get_attribute(instance) def to_representation(self, value): - if isinstance(value, QuerySet): + if isinstance(value, collections.Iterable): base = super(SerializerMethodResourceRelatedField, self) return [base.to_representation(x) for x in value] - return super(SerializerMethodResourceRelatedField, self).to_representation(value) - - def get_links(self, obj=None, lookup_field='pk'): - return OrderedDict() + return super(SerializerMethodResourceRelatedField, self).to_representation(value) \ No newline at end of file