1616from tests .serializers import BasicModelSerializer , ForeignKeyTargetSerializer
1717from tests .views import (
1818 BasicModelViewSet ,
19+ ForeignKeySourcetHyperlinkedViewSet ,
1920 ForeignKeySourceViewSet ,
21+ ForeignKeyTargetViewSet ,
2022 ManyToManySourceViewSet ,
2123 NestedRelatedSourceViewSet ,
2224)
@@ -87,7 +89,7 @@ def test_list(self, client, model):
8789
8890 @pytest .mark .urls (__name__ )
8991 def test_list_with_include_foreign_key (self , client , foreign_key_source ):
90- url = reverse ("foreign-key-source -list" )
92+ url = reverse ("foreignkeysource -list" )
9193 response = client .get (url , data = {"include" : "target" })
9294 assert response .status_code == status .HTTP_200_OK
9395 result = response .json ()
@@ -156,7 +158,7 @@ def test_list_with_include_nested_related_field(
156158
157159 @pytest .mark .urls (__name__ )
158160 def test_list_with_invalid_include (self , client , foreign_key_source ):
159- url = reverse ("foreign-key-source -list" )
161+ url = reverse ("foreignkeysource -list" )
160162 response = client .get (url , data = {"include" : "invalid" })
161163 assert response .status_code == status .HTTP_400_BAD_REQUEST
162164 result = response .json ()
@@ -195,7 +197,7 @@ def test_retrieve(self, client, model):
195197
196198 @pytest .mark .urls (__name__ )
197199 def test_retrieve_with_include_foreign_key (self , client , foreign_key_source ):
198- url = reverse ("foreign-key-source -detail" , kwargs = {"pk" : foreign_key_source .pk })
200+ url = reverse ("foreignkeysource -detail" , kwargs = {"pk" : foreign_key_source .pk })
199201 response = client .get (url , data = {"include" : "target" })
200202 assert response .status_code == status .HTTP_200_OK
201203 result = response .json ()
@@ -208,6 +210,20 @@ def test_retrieve_with_include_foreign_key(self, client, foreign_key_source):
208210 }
209211 ] == result ["included" ]
210212
213+ @pytest .mark .urls (__name__ )
214+ def test_retrieve_hyperlinked_with_sparse_fields (self , client , foreign_key_source ):
215+ url = reverse (
216+ "foreignkeysourcehyperlinked-detail" , kwargs = {"pk" : foreign_key_source .pk }
217+ )
218+ response = client .get (url , data = {"fields[ForeignKeySource]" : "name" })
219+ assert response .status_code == status .HTTP_200_OK
220+ data = response .json ()["data" ]
221+ assert data ["attributes" ] == {"name" : foreign_key_source .name }
222+ assert "relationships" not in data
223+ assert data ["links" ] == {
224+ "self" : f"http://testserver/foreign_key_sources/{ foreign_key_source .pk } /"
225+ }
226+
211227 @pytest .mark .urls (__name__ )
212228 def test_patch (self , client , model ):
213229 data = {
@@ -239,7 +255,7 @@ def test_delete(self, client, model):
239255
240256 @pytest .mark .urls (__name__ )
241257 def test_create_with_sparse_fields (self , client , foreign_key_target ):
242- url = reverse ("foreign-key-source -list" )
258+ url = reverse ("foreignkeysource -list" )
243259 data = {
244260 "data" : {
245261 "id" : None ,
@@ -379,6 +395,28 @@ def test_patch_with_custom_id(self, client):
379395 }
380396 }
381397
398+ @pytest .mark .urls (__name__ )
399+ def test_patch_with_custom_id_with_sparse_fields (self , client ):
400+ data = {
401+ "data" : {
402+ "id" : 2_193_102 ,
403+ "type" : "custom" ,
404+ "attributes" : {"body" : "hello" },
405+ }
406+ }
407+
408+ url = reverse ("custom-id" )
409+
410+ response = client .patch (f"{ url } ?fields[custom]=body" , data = data )
411+ assert response .status_code == status .HTTP_200_OK
412+ assert response .json () == {
413+ "data" : {
414+ "type" : "custom" ,
415+ "id" : "2176ce" , # get_id() -> hex
416+ "attributes" : {"body" : "hello" },
417+ }
418+ }
419+
382420
383421# Routing setup
384422
@@ -415,13 +453,16 @@ class CustomModelSerializer(serializers.Serializer):
415453 id = serializers .IntegerField ()
416454
417455
418- class CustomIdModelSerializer (serializers .Serializer ):
456+ class CustomIdSerializer (serializers .Serializer ):
419457 id = serializers .SerializerMethodField ()
420458 body = serializers .CharField ()
421459
422460 def get_id (self , obj ):
423461 return hex (obj .id )[2 :]
424462
463+ class Meta :
464+ resource_name = "custom"
465+
425466
426467class CustomAPIView (APIView ):
427468 parser_classes = [JSONParser ]
@@ -443,14 +484,23 @@ class CustomIdAPIView(APIView):
443484 resource_name = "custom"
444485
445486 def patch (self , request , * args , ** kwargs ):
446- serializer = CustomIdModelSerializer (CustomModel (request .data ))
487+ serializer = CustomIdSerializer (
488+ CustomModel (request .data ), context = {"request" : self .request }
489+ )
447490 return Response (status = status .HTTP_200_OK , data = serializer .data )
448491
449492
493+ # TODO remove basename and use default (lowercase of model)
494+ # this makes using HyperlinkedIdentityField easier and reduces
495+ # configuration in general
450496router = SimpleRouter ()
451497router .register (r"basic_models" , BasicModelViewSet , basename = "basic-model" )
498+ router .register (r"foreign_key_sources" , ForeignKeySourceViewSet )
499+ router .register (r"foreign_key_targets" , ForeignKeyTargetViewSet )
452500router .register (
453- r"foreign_key_sources" , ForeignKeySourceViewSet , basename = "foreign-key-source"
501+ r"foreign_key_sources_hyperlinked" ,
502+ ForeignKeySourcetHyperlinkedViewSet ,
503+ "foreignkeysourcehyperlinked" ,
454504)
455505router .register (
456506 r"many_to_many_sources" , ManyToManySourceViewSet , basename = "many-to-many-source"
0 commit comments