diff --git a/docs/topics/2.3-announcement.md b/docs/topics/2.3-announcement.md index e1bcde051..450955824 100644 --- a/docs/topics/2.3-announcement.md +++ b/docs/topics/2.3-announcement.md @@ -138,7 +138,7 @@ Note that the relevant methods have always been private APIs, and the docstrings ## Explict view attributes -The usage of `model` attribute in generic Views is still supported, but it's usage is being discouraged in favour of using explict `queryset` and `serializer_class` attributes. +The usage of `model` attribute in generic Views is still supported, but it's usage is being discouraged in favour of the more explict `queryset` attribute. For example, the following is now the recommended style for using generic views: @@ -146,9 +146,9 @@ For example, the following is now the recommended style for using generic views: queryset = MyModel.objects.all() serializer_class = MyModelSerializer -Using explict `queryset` and `serializer_class` attributes makes the functioning of the view more clear than using the shortcut `model` attribute. +Using an explict `queryset` attribute makes the functioning of the view more clear than using the shortcut `model` attribute. -It also makes it the usage of overridden `get_queryset()` or `get_serializer_class()` methods more obvious. +It also makes the usage of an overridden `get_queryset()` method more obvious. class AccountListView(generics.RetrieveAPIView): serializer_class = MyModelSerializer diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 0b8e4a157..3ea78b5d3 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -48,11 +48,10 @@ class GenericAPIView(views.APIView): # attribute, although using the explicit style is generally preferred. fields = None - # If the `model` shortcut is used instead of `serializer_class`, then the - # serializer class will be constructed using this class as the base. + # The following attributes may be subject to change, + # and should be considered private API. model_serializer_class = api_settings.DEFAULT_MODEL_SERIALIZER_CLASS - - _paginator_class = Paginator + paginator_class = Paginator ###################################### # These are pending deprecation... @@ -115,8 +114,8 @@ class GenericAPIView(views.APIView): if not page_size: return None - paginator = self._paginator_class(queryset, page_size, - allow_empty_first_page=self.allow_empty) + paginator = self.paginator_class(queryset, page_size, + allow_empty_first_page=self.allow_empty) page_kwarg = self.kwargs.get(self.page_kwarg) page_query_param = self.request.QUERY_PARAMS.get(self.page_kwarg) page = page_kwarg or page_query_param or 1 @@ -194,9 +193,15 @@ class GenericAPIView(views.APIView): if serializer_class is not None: return serializer_class + assert self.model is not None or self.queryset is not None, \ + "'%s' should either include a 'serializer_class' attribute, " \ + "or use the 'queryset' or 'model' attribute as a shortcut for " \ + "automatically generating a serializer class." \ + % self.__class__.__name__ + class DefaultSerializer(self.model_serializer_class): class Meta: - model = self.model + model = self.model or self.queryset.model fields = self.fields return DefaultSerializer diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index 12c9b6778..63ff1fc32 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -350,11 +350,11 @@ class TestFieldsShortcut(TestCase): """ def setUp(self): class OverriddenFieldsView(generics.RetrieveUpdateDestroyAPIView): - model = BasicModel + queryset = BasicModel.objects.all() fields = ('text',) class RegularView(generics.RetrieveUpdateDestroyAPIView): - model = BasicModel + queryset = BasicModel.objects.all() self.overridden_fields_view = OverriddenFieldsView() self.regular_view = RegularView() @@ -362,10 +362,12 @@ class TestFieldsShortcut(TestCase): def test_overridden_fields_view(self): Serializer = self.overridden_fields_view.get_serializer_class() self.assertEqual(Serializer().fields.keys(), ['text']) + self.assertEqual(Serializer().opts.model, BasicModel) def test_not_overridden_fields_view(self): Serializer = self.regular_view.get_serializer_class() self.assertEqual(Serializer().fields.keys(), ['id', 'text']) + self.assertEqual(Serializer().opts.model, BasicModel) # Regression test for #285