Tweaks for preferring .queryset over .model

This commit is contained in:
Tom Christie 2013-04-29 14:08:38 +01:00
parent 53f9d4a380
commit 0c1ab584d3
3 changed files with 19 additions and 12 deletions

View File

@ -138,7 +138,7 @@ Note that the relevant methods have always been private APIs, and the docstrings
## Explict view attributes ## 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: 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() queryset = MyModel.objects.all()
serializer_class = MyModelSerializer 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): class AccountListView(generics.RetrieveAPIView):
serializer_class = MyModelSerializer serializer_class = MyModelSerializer

View File

@ -48,11 +48,10 @@ class GenericAPIView(views.APIView):
# attribute, although using the explicit style is generally preferred. # attribute, although using the explicit style is generally preferred.
fields = None fields = None
# If the `model` shortcut is used instead of `serializer_class`, then the # The following attributes may be subject to change,
# serializer class will be constructed using this class as the base. # and should be considered private API.
model_serializer_class = api_settings.DEFAULT_MODEL_SERIALIZER_CLASS model_serializer_class = api_settings.DEFAULT_MODEL_SERIALIZER_CLASS
paginator_class = Paginator
_paginator_class = Paginator
###################################### ######################################
# These are pending deprecation... # These are pending deprecation...
@ -115,8 +114,8 @@ class GenericAPIView(views.APIView):
if not page_size: if not page_size:
return None return None
paginator = self._paginator_class(queryset, page_size, paginator = self.paginator_class(queryset, page_size,
allow_empty_first_page=self.allow_empty) allow_empty_first_page=self.allow_empty)
page_kwarg = self.kwargs.get(self.page_kwarg) page_kwarg = self.kwargs.get(self.page_kwarg)
page_query_param = self.request.QUERY_PARAMS.get(self.page_kwarg) page_query_param = self.request.QUERY_PARAMS.get(self.page_kwarg)
page = page_kwarg or page_query_param or 1 page = page_kwarg or page_query_param or 1
@ -194,9 +193,15 @@ class GenericAPIView(views.APIView):
if serializer_class is not None: if serializer_class is not None:
return serializer_class 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 DefaultSerializer(self.model_serializer_class):
class Meta: class Meta:
model = self.model model = self.model or self.queryset.model
fields = self.fields fields = self.fields
return DefaultSerializer return DefaultSerializer

View File

@ -350,11 +350,11 @@ class TestFieldsShortcut(TestCase):
""" """
def setUp(self): def setUp(self):
class OverriddenFieldsView(generics.RetrieveUpdateDestroyAPIView): class OverriddenFieldsView(generics.RetrieveUpdateDestroyAPIView):
model = BasicModel queryset = BasicModel.objects.all()
fields = ('text',) fields = ('text',)
class RegularView(generics.RetrieveUpdateDestroyAPIView): class RegularView(generics.RetrieveUpdateDestroyAPIView):
model = BasicModel queryset = BasicModel.objects.all()
self.overridden_fields_view = OverriddenFieldsView() self.overridden_fields_view = OverriddenFieldsView()
self.regular_view = RegularView() self.regular_view = RegularView()
@ -362,10 +362,12 @@ class TestFieldsShortcut(TestCase):
def test_overridden_fields_view(self): def test_overridden_fields_view(self):
Serializer = self.overridden_fields_view.get_serializer_class() Serializer = self.overridden_fields_view.get_serializer_class()
self.assertEqual(Serializer().fields.keys(), ['text']) self.assertEqual(Serializer().fields.keys(), ['text'])
self.assertEqual(Serializer().opts.model, BasicModel)
def test_not_overridden_fields_view(self): def test_not_overridden_fields_view(self):
Serializer = self.regular_view.get_serializer_class() Serializer = self.regular_view.get_serializer_class()
self.assertEqual(Serializer().fields.keys(), ['id', 'text']) self.assertEqual(Serializer().fields.keys(), ['id', 'text'])
self.assertEqual(Serializer().opts.model, BasicModel)
# Regression test for #285 # Regression test for #285