11from __future__ import absolute_import
22
3+ from django .test .client import RequestFactory
34from django .utils import timezone
45from rest_framework import serializers
6+ from rest_framework .fields import SkipField
7+ from rest_framework .reverse import reverse
58
69from rest_framework_json_api .exceptions import Conflict
7- from rest_framework_json_api .relations import ResourceRelatedField
10+ from rest_framework_json_api .relations import (
11+ HyperLinkedRelatedField ,
12+ ResourceRelatedField ,
13+ SerializerMethodHyperLinkedRelatedField
14+ )
815from rest_framework_json_api .utils import format_resource_type
916
1017from . import TestBase
1118from example .models import Author , Blog , Comment , Entry
1219from example .serializers import CommentSerializer
20+ from example .views import EntryViewSet
1321
1422
1523class TestResourceRelatedField (TestBase ):
@@ -129,6 +137,117 @@ def test_invalid_resource_id_object(self):
129137 }
130138
131139
140+ class TestHyperLinkedFieldBase (TestBase ):
141+
142+ def setUp (self ):
143+ super (TestHyperLinkedFieldBase , self ).setUp ()
144+ self .blog = Blog .objects .create (name = 'Some Blog' , tagline = "It's a blog" )
145+ self .entry = Entry .objects .create (
146+ blog = self .blog ,
147+ headline = 'headline' ,
148+ body_text = 'body_text' ,
149+ pub_date = timezone .now (),
150+ mod_date = timezone .now (),
151+ n_comments = 0 ,
152+ n_pingbacks = 0 ,
153+ rating = 3
154+ )
155+ self .comment = Comment .objects .create (
156+ entry = self .entry ,
157+ body = 'testing one two three' ,
158+ )
159+
160+ self .request = RequestFactory ().get (reverse ('entry-detail' , kwargs = {'pk' : self .entry .pk }))
161+ self .view = EntryViewSet (request = self .request , kwargs = {'entry_pk' : self .entry .id })
162+
163+
164+ class TestHyperLinkedRelatedField (TestHyperLinkedFieldBase ):
165+
166+ def test_single_hyperlinked_related_field (self ):
167+ field = HyperLinkedRelatedField (
168+ related_link_view_name = 'entry-blog' ,
169+ related_link_url_kwarg = 'entry_pk' ,
170+ self_link_view_name = 'entry-relationships' ,
171+ read_only = True ,
172+ )
173+ field ._context = {'request' : self .request , 'view' : self .view }
174+ field .field_name = 'blog'
175+
176+ self .assertRaises (NotImplementedError , field .to_representation , self .entry )
177+ self .assertRaises (SkipField , field .get_attribute , self .entry )
178+
179+ links_expected = {
180+ 'self' : 'http://testserver/entries/{}/relationships/blog' .format (self .entry .pk ),
181+ 'related' : 'http://testserver/entries/{}/blog' .format (self .entry .pk )
182+ }
183+ got = field .get_links (self .entry )
184+ self .assertEqual (got , links_expected )
185+
186+ def test_many_hyperlinked_related_field (self ):
187+ field = HyperLinkedRelatedField (
188+ related_link_view_name = 'entry-comments' ,
189+ related_link_url_kwarg = 'entry_pk' ,
190+ self_link_view_name = 'entry-relationships' ,
191+ read_only = True ,
192+ many = True
193+ )
194+ field ._context = {'request' : self .request , 'view' : self .view }
195+ field .field_name = 'comments'
196+
197+ self .assertRaises (NotImplementedError , field .to_representation , self .entry .comments .all ())
198+ self .assertRaises (SkipField , field .get_attribute , self .entry )
199+
200+ links_expected = {
201+ 'self' : 'http://testserver/entries/{}/relationships/comments' .format (self .entry .pk ),
202+ 'related' : 'http://testserver/entries/{}/comments' .format (self .entry .pk )
203+ }
204+ got = field .child_relation .get_links (self .entry )
205+ self .assertEqual (got , links_expected )
206+
207+
208+ class TestSerializerMethodHyperLinkedRelatedField (TestHyperLinkedFieldBase ):
209+
210+ def test_single_serializer_method_hyperlinked_related_field (self ):
211+ serializer = EntryModelSerializerWithHyperLinks (
212+ instance = self .entry ,
213+ context = {
214+ 'request' : self .request ,
215+ 'view' : self .view
216+ }
217+ )
218+ field = serializer .fields ['blog' ]
219+
220+ self .assertRaises (NotImplementedError , field .to_representation , self .entry )
221+ self .assertRaises (SkipField , field .get_attribute , self .entry )
222+
223+ expected = {
224+ 'self' : 'http://testserver/entries/{}/relationships/blog' .format (self .entry .pk ),
225+ 'related' : 'http://testserver/entries/{}/blog' .format (self .entry .pk )
226+ }
227+ got = field .get_links (self .entry )
228+ self .assertEqual (got , expected )
229+
230+ def test_many_serializer_method_hyperlinked_related_field (self ):
231+ serializer = EntryModelSerializerWithHyperLinks (
232+ instance = self .entry ,
233+ context = {
234+ 'request' : self .request ,
235+ 'view' : self .view
236+ }
237+ )
238+ field = serializer .fields ['comments' ]
239+
240+ self .assertRaises (NotImplementedError , field .to_representation , self .entry )
241+ self .assertRaises (SkipField , field .get_attribute , self .entry )
242+
243+ expected = {
244+ 'self' : 'http://testserver/entries/{}/relationships/comments' .format (self .entry .pk ),
245+ 'related' : 'http://testserver/entries/{}/comments' .format (self .entry .pk )
246+ }
247+ got = field .get_links (self .entry )
248+ self .assertEqual (got , expected )
249+
250+
132251class BlogResourceRelatedField (ResourceRelatedField ):
133252 def get_queryset (self ):
134253 return Blog .objects
@@ -149,3 +268,32 @@ class EntryModelSerializer(serializers.ModelSerializer):
149268 class Meta :
150269 model = Entry
151270 fields = ('authors' , 'comments' )
271+
272+
273+ class EntryModelSerializerWithHyperLinks (serializers .ModelSerializer ):
274+ blog = SerializerMethodHyperLinkedRelatedField (
275+ related_link_view_name = 'entry-blog' ,
276+ related_link_url_kwarg = 'entry_pk' ,
277+ self_link_view_name = 'entry-relationships' ,
278+ many = True ,
279+ read_only = True ,
280+ source = 'get_blog'
281+ )
282+ comments = SerializerMethodHyperLinkedRelatedField (
283+ related_link_view_name = 'entry-comments' ,
284+ related_link_url_kwarg = 'entry_pk' ,
285+ self_link_view_name = 'entry-relationships' ,
286+ many = True ,
287+ read_only = True ,
288+ source = 'get_comments'
289+ )
290+
291+ class Meta :
292+ model = Entry
293+ fields = ('blog' , 'comments' ,)
294+
295+ def get_blog (self , obj ):
296+ return obj .blog
297+
298+ def get_authors (self , obj ):
299+ return obj .comments .all ()
0 commit comments