diff --git a/AUTHORS b/AUTHORS index 6a90ff25..b34f17c6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,6 +6,7 @@ Greg Aker Jamie Bliss Jerel Unruh Léo S. +Luc Cary Matt Layman Ola Tarkowska Oliver Sauder diff --git a/CHANGELOG.md b/CHANGELOG.md index 21513fda..61d85b52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ v2.5.0 - [unreleased] * Add new pagination classes based on JSON:API query parameter *recommendations*: * JsonApiPageNumberPagination and JsonApiLimitOffsetPagination. See [usage docs](docs/usage.md#pagination). * Deprecates PageNumberPagination and LimitOffsetPagination. +* Add ReadOnlyModelViewSet extension with prefetch mixins. v2.4.0 - Released January 25, 2018 diff --git a/docs/usage.md b/docs/usage.md index c0d8d21e..990638f9 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -612,19 +612,29 @@ class QuestSerializer(serializers.ModelSerializer): #### Performance improvements -Be aware that using included resources without any form of prefetching **WILL HURT PERFORMANCE** as it will introduce m*(n+1) queries. +Be aware that using included resources without any form of prefetching **WILL HURT PERFORMANCE** as it will introduce m\*(n+1) queries. A viewset helper was designed to allow for greater flexibility and it is automatically available when subclassing -`views.ModelViewSet` -``` - # When MyViewSet is called with ?include=author it will dynamically prefetch author and author.bio - class MyViewSet(viewsets.ModelViewSet): +`rest_framework_json_api.views.ModelViewSet`: +```python +from rest_framework_json_api import views + +# When MyViewSet is called with ?include=author it will dynamically prefetch author and author.bio +class MyViewSet(views.ModelViewSet): queryset = Book.objects.all() prefetch_for_includes = { - '__all__': [], - 'author': ['author', 'author__bio'] - 'category.section': ['category'] -} + '__all__': [], + 'author': ['author', 'author__bio'], + 'category.section': ['category'] + } +``` + +An additional convenience DJA class exists for read-only views, just as it does in DRF. +```python +from rest_framework_json_api import views + +class MyReadOnlyViewSet(views.ReadOnlyModelViewSet): + # ... ``` The special keyword `__all__` can be used to specify a prefetch which should be done regardless of the include, similar to making the prefetch yourself on the QuerySet. diff --git a/example/tests/unit/test_renderers.py b/example/tests/unit/test_renderers.py index 495bf99f..de40afac 100644 --- a/example/tests/unit/test_renderers.py +++ b/example/tests/unit/test_renderers.py @@ -33,14 +33,31 @@ class DummyTestViewSet(views.ModelViewSet): serializer_class = DummyTestSerializer +class ReadOnlyDummyTestViewSet(views.ReadOnlyModelViewSet): + queryset = Entry.objects.all() + serializer_class = DummyTestSerializer + + +def render_dummy_test_serialized_view(view_class): + serializer = DummyTestSerializer(instance=Entry()) + renderer = JSONRenderer() + return renderer.render( + serializer.data, + renderer_context={'view': view_class()}) + + def test_simple_reverse_relation_included_renderer(): ''' Test renderer when a single reverse fk relation is passed. ''' - serializer = DummyTestSerializer(instance=Entry()) - renderer = JSONRenderer() - rendered = renderer.render( - serializer.data, - renderer_context={'view': DummyTestViewSet()}) + rendered = render_dummy_test_serialized_view( + DummyTestViewSet) + + assert rendered + + +def test_simple_reverse_relation_included_read_only_viewset(): + rendered = render_dummy_test_serialized_view( + ReadOnlyDummyTestViewSet) assert rendered diff --git a/rest_framework_json_api/views.py b/rest_framework_json_api/views.py index 0156bccc..64e5d12e 100644 --- a/rest_framework_json_api/views.py +++ b/rest_framework_json_api/views.py @@ -38,7 +38,7 @@ class MyViewSet(viewsets.ModelViewSet): queryset = Book.objects.all() prefetch_for_includes = { '__all__': [], - 'author': ['author', 'author__authorbio'] + 'author': ['author', 'author__authorbio'], 'category.section': ['category'] } """ @@ -102,6 +102,12 @@ class ModelViewSet(AutoPrefetchMixin, PrefetchForIncludesHelperMixin, viewsets.M pass +class ReadOnlyModelViewSet(AutoPrefetchMixin, + PrefetchForIncludesHelperMixin, + viewsets.ReadOnlyModelViewSet): + pass + + class RelationshipView(generics.GenericAPIView): serializer_class = ResourceIdentifierObjectSerializer self_link_view_name = None