Skip to content

Commit 0260c6c

Browse files
committed
Added RelatedMixin
1 parent ffe61c6 commit 0260c6c

File tree

5 files changed

+75
-2
lines changed

5 files changed

+75
-2
lines changed

example/serializers.py

+11
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,17 @@ class Meta:
155155

156156

157157
class AuthorSerializer(serializers.ModelSerializer):
158+
bio = relations.ResourceRelatedField(
159+
related_link_view_name='author-related',
160+
self_link_view_name='author-relationships',
161+
queryset=AuthorBio.objects,
162+
)
163+
entries = relations.ResourceRelatedField(
164+
related_link_view_name='author-related',
165+
self_link_view_name='author-relationships',
166+
queryset=Entry.objects,
167+
many=True
168+
)
158169
included_serializers = {
159170
'bio': AuthorBioSerializer,
160171
'type': AuthorTypeSerializer

example/urls.py

+4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
EntryViewSet.as_view({'get': 'retrieve'}),
4646
name='entry-featured'),
4747

48+
url(r'^authors/(?P<pk>[^/.]+)/(?P<related_field>\w+)/$',
49+
AuthorViewSet.as_view({'get': 'retrieve_related'}),
50+
name='author-related'),
51+
4852
url(r'^entries/(?P<pk>[^/.]+)/relationships/(?P<related_field>\w+)',
4953
EntryRelationshipView.as_view(),
5054
name='entry-relationships'),

example/urls_test.py

+4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@
5656
EntryViewSet.as_view({'get': 'retrieve'}),
5757
name='entry-featured'),
5858

59+
url(r'^authors/(?P<pk>[^/.]+)/(?P<related_field>\w+)/$',
60+
AuthorViewSet.as_view({'get': 'retrieve_related'}),
61+
name='author-related'),
62+
5963
url(r'^entries/(?P<pk>[^/.]+)/relationships/(?P<related_field>\w+)',
6064
EntryRelationshipView.as_view(),
6165
name='entry-relationships'),

example/views.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
import rest_framework_json_api.renderers
88
from rest_framework_json_api.pagination import PageNumberPagination
99
from rest_framework_json_api.utils import format_drf_errors
10-
from rest_framework_json_api.views import ModelViewSet, RelationshipView
10+
from rest_framework_json_api.views import ModelViewSet, RelatedMixin, RelationshipView
1111

1212
from example.models import Author, Blog, Comment, Company, Entry, Project
1313
from example.serializers import (
14+
AuthorBioSerializer,
1415
AuthorSerializer,
1516
BlogSerializer,
1617
CommentSerializer,
@@ -92,9 +93,13 @@ class NonPaginatedEntryViewSet(EntryViewSet):
9293
pagination_class = NoPagination
9394

9495

95-
class AuthorViewSet(ModelViewSet):
96+
class AuthorViewSet(RelatedMixin, ModelViewSet):
9697
queryset = Author.objects.all()
9798
serializer_class = AuthorSerializer
99+
related_serializers = {
100+
'bio': AuthorBioSerializer,
101+
'entries': EntrySerializer
102+
}
98103

99104

100105
class CommentViewSet(ModelViewSet):

rest_framework_json_api/views.py

+49
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from collections import Iterable
12
from django.core.exceptions import ImproperlyConfigured
23
from django.db.models import Model
34
from django.db.models.fields.related_descriptors import (
@@ -98,6 +99,54 @@ def get_queryset(self, *args, **kwargs):
9899
return qs
99100

100101

102+
class RelatedMixin(object):
103+
"""
104+
This mixin handles all related entities, whose Serializers are declared in "related_serializers"
105+
"""
106+
related_serializers = {}
107+
field_name_mapping = {}
108+
109+
def retrieve_related(self, request, *args, **kwargs):
110+
serializer_kwargs = {}
111+
instance = self.get_related_instance()
112+
113+
if hasattr(instance, 'all'):
114+
instance = instance.all()
115+
116+
if callable(instance):
117+
instance = instance()
118+
119+
if instance is None:
120+
return Response(data=None)
121+
122+
if isinstance(instance, Iterable):
123+
serializer_kwargs['many'] = True
124+
125+
serializer = self.get_serializer(instance, **serializer_kwargs)
126+
return Response(serializer.data)
127+
128+
def get_serializer_class(self):
129+
if 'related_field' in self.kwargs:
130+
field_name = self.get_related_field_name()
131+
_class = self.related_serializers.get(field_name, None)
132+
if _class is None:
133+
raise NotFound
134+
return _class
135+
return super(RelatedMixin, self).get_serializer_class()
136+
137+
def get_related_field_name(self):
138+
field_name = self.kwargs['related_field']
139+
if field_name in self.field_name_mapping:
140+
return self.field_name_mapping[field_name]
141+
return field_name
142+
143+
def get_related_instance(self):
144+
try:
145+
return getattr(self.get_object(), self.get_related_field_name())
146+
except AttributeError:
147+
raise NotFound
148+
149+
101150
class ModelViewSet(AutoPrefetchMixin, PrefetchForIncludesHelperMixin, viewsets.ModelViewSet):
102151
pass
103152

0 commit comments

Comments
 (0)