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 72feb47

Browse files
committed
Updated SerializerMethodResourceRelatedField to allow many=True
Issue #151 Closes #220
1 parent 0ed1667 commit 72feb47

File tree

4 files changed

+59
-39
lines changed

4 files changed

+59
-39
lines changed

‎example/serializers.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,19 @@ def __init__(self, *args, **kwargs):
3838
}
3939

4040
body_format = serializers.SerializerMethodField()
41+
# many related from model
4142
comments = relations.ResourceRelatedField(
4243
source='comment_set', many=True, read_only=True)
44+
# many related from serializer
45+
suggested = relations.SerializerMethodResourceRelatedField(
46+
source='get_suggested', model=Entry, many=True, read_only=True)
47+
# single related from serializer
4348
featured = relations.SerializerMethodResourceRelatedField(
4449
source='get_featured', model=Entry, read_only=True)
4550

51+
def get_suggested(self, obj):
52+
return Entry.objects.exclude(pk=obj.pk)
53+
4654
def get_featured(self, obj):
4755
return Entry.objects.exclude(pk=obj.pk).first()
4856

@@ -52,7 +60,7 @@ def get_body_format(self, obj):
5260
class Meta:
5361
model = Entry
5462
fields = ('blog', 'headline', 'body_text', 'pub_date', 'mod_date',
55-
'authors', 'comments', 'featured',)
63+
'authors', 'comments', 'featured','suggested',)
5664
meta_fields = ('body_format',)
5765

5866

‎example/tests/integration/test_non_paginated_responses.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ def test_multiple_entries_no_pagination(multiple_entries, rf):
4141
"comments": {
4242
"meta": {"count": 1},
4343
"data": [{"type": "comments", "id": "1"}]
44+
},
45+
"suggested": {
46+
"data": [{"type": "entries", "id": "2"}]
4447
}
4548
}
4649
},
@@ -69,6 +72,9 @@ def test_multiple_entries_no_pagination(multiple_entries, rf):
6972
"comments": {
7073
"meta": {"count": 1},
7174
"data": [{"type": "comments", "id": "2"}]
75+
},
76+
"suggested": {
77+
"data": [{"type": "entries", "id": "1"}]
7278
}
7379
}
7480
},

‎example/tests/integration/test_pagination.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ def test_pagination_with_single_entry(single_entry, client):
3535
"comments": {
3636
"meta": {"count": 1},
3737
"data": [{"type": "comments", "id": "1"}]
38+
},
39+
"suggested": {
40+
"data": []
3841
}
3942
}
4043
}],

‎rest_framework_json_api/relations.py‎

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,13 @@
33
from rest_framework.fields import MISSING_ERROR_MESSAGE
44
from rest_framework.relations import *
55
from django.utils.translation import ugettext_lazy as _
6+
from django.db.models.query import QuerySet
67

78
from rest_framework_json_api.exceptions import Conflict
89
from rest_framework_json_api.utils import Hyperlink, \
910
get_resource_type_from_queryset, get_resource_type_from_instance, \
1011
get_included_serializers, get_resource_type_from_serializer
1112

12-
import pdb
13-
14-
JSONAPI_MANY_RELATION_KWARGS = ('model', ) + MANY_RELATION_KWARGS
15-
16-
class ManyResourceRelatedField(ManyRelatedField):
17-
"""
18-
Allows us to use serializer method RelatedFields
19-
with return querysets
20-
"""
21-
def __init__(self, child_relation=None, *args, **kwargs):
22-
model = kwargs.pop('model', None)
23-
if model:
24-
self.model = model
25-
super(ManyResourceRelatedField, self).__init__(child_relation, *args, **kwargs)
26-
27-
def get_attribute(self, instance):
28-
if self.source and hasattr(self.parent, self.source):
29-
serializer_method = getattr(self.parent, self.source)
30-
if hasattr(serializer_method, '__call__'):
31-
return serializer_method(instance)
32-
return super(ManyResourceRelatedField, self).get_attribute(instance)
33-
3413

3514
class ResourceRelatedField(PrimaryKeyRelatedField):
3615
self_link_view_name = None
@@ -47,21 +26,6 @@ class ResourceRelatedField(PrimaryKeyRelatedField):
4726
'no_match': _('Invalid hyperlink - No URL match.'),
4827
}
4928

50-
def __new__(cls, *args, **kwargs):
51-
# We override this because getting
52-
# serializer methods fails when many is true
53-
if kwargs.pop('many', False):
54-
return cls.many_init(*args, **kwargs)
55-
return super(ResourceRelatedField, cls).__new__(cls, *args, **kwargs)
56-
57-
@classmethod
58-
def many_init(cls, *args, **kwargs):
59-
list_kwargs = {'child_relation': cls(*args, **kwargs)}
60-
for key in kwargs.keys():
61-
if key in JSONAPI_MANY_RELATION_KWARGS:
62-
list_kwargs[key] = kwargs[key]
63-
return ManyResourceRelatedField(**list_kwargs)
64-
6529
def __init__(self, self_link_view_name=None, related_link_view_name=None, **kwargs):
6630
if self_link_view_name is not None:
6731
self.self_link_view_name = self_link_view_name
@@ -205,11 +169,50 @@ def choices(self):
205169
])
206170

207171

172+
208173
class SerializerMethodResourceRelatedField(ResourceRelatedField):
174+
"""
175+
Allows us to use serializer method RelatedFields
176+
with return querysets
177+
"""
178+
def __new__(cls, *args, **kwargs):
179+
"""
180+
We override this because getting serializer methods
181+
fails at the base class when many=True
182+
"""
183+
if kwargs.pop('many', False):
184+
return cls.many_init(*args, **kwargs)
185+
return super(ResourceRelatedField, cls).__new__(cls, *args, **kwargs)
186+
187+
def __init__(self, child_relation=None, *args, **kwargs):
188+
# DRF 3.1 doesn't expect the `many` kwarg
189+
kwargs.pop('many', None)
190+
model = kwargs.pop('model', None)
191+
if model:
192+
self.model = model
193+
super(SerializerMethodResourceRelatedField, self).__init__(child_relation, *args, **kwargs)
194+
195+
@classmethod
196+
def many_init(cls, *args, **kwargs):
197+
list_kwargs = {'child_relation': cls(*args, **kwargs)}
198+
for key in kwargs.keys():
199+
if key in ('model',) + MANY_RELATION_KWARGS:
200+
list_kwargs[key] = kwargs[key]
201+
return SerializerMethodResourceRelatedField(**list_kwargs)
202+
209203
def get_attribute(self, instance):
210204
# check for a source fn defined on the serializer instead of the model
211205
if self.source and hasattr(self.parent, self.source):
212206
serializer_method = getattr(self.parent, self.source)
213207
if hasattr(serializer_method, '__call__'):
214208
return serializer_method(instance)
215-
return super(ResourceRelatedField, self).get_attribute(instance)
209+
return super(SerializerMethodResourceRelatedField, self).get_attribute(instance)
210+
211+
def to_representation(self, value):
212+
if isinstance(value, QuerySet):
213+
base = super(SerializerMethodResourceRelatedField, self)
214+
return [base.to_representation(x) for x in value]
215+
return super(SerializerMethodResourceRelatedField, self).to_representation(value)
216+
217+
def get_links(self, obj=None, lookup_field='pk'):
218+
return OrderedDict()

0 commit comments

Comments
(0)

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