Skip to content

Commit 196d8ba

Browse files
committed
Added RelatedMixin
1 parent ffe61c6 commit 196d8ba

File tree

5 files changed

+76
-2
lines changed

5 files changed

+76
-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

+50
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from collections import Iterable
2+
13
from django.core.exceptions import ImproperlyConfigured
24
from django.db.models import Model
35
from django.db.models.fields.related_descriptors import (
@@ -98,6 +100,54 @@ def get_queryset(self, *args, **kwargs):
98100
return qs
99101

100102

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

0 commit comments

Comments
 (0)