aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework/generics.py
diff options
context:
space:
mode:
Diffstat (limited to 'rest_framework/generics.py')
-rw-r--r--rest_framework/generics.py98
1 files changed, 55 insertions, 43 deletions
diff --git a/rest_framework/generics.py b/rest_framework/generics.py
index 7bac510f..77deb8e4 100644
--- a/rest_framework/generics.py
+++ b/rest_framework/generics.py
@@ -25,6 +25,7 @@ def strict_positive_int(integer_string, cutoff=None):
ret = min(ret, cutoff)
return ret
+
def get_object_or_404(queryset, *filter_args, **filter_kwargs):
"""
Same as Django's standard shortcut, but make sure to raise 404
@@ -43,6 +44,10 @@ class GenericAPIView(views.APIView):
# You'll need to either set these attributes,
# or override `get_queryset()`/`get_serializer_class()`.
+ # If you are overriding a view method, it is important that you call
+ # `get_queryset()` instead of accessing the `queryset` property directly,
+ # as `queryset` will get evaluated only once, and those results are cached
+ # for all subsequent requests.
queryset = None
serializer_class = None
@@ -90,8 +95,8 @@ class GenericAPIView(views.APIView):
'view': self
}
- def get_serializer(self, instance=None, data=None,
- files=None, many=False, partial=False):
+ def get_serializer(self, instance=None, data=None, files=None, many=False,
+ partial=False, allow_add_remove=False):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
@@ -99,7 +104,9 @@ class GenericAPIView(views.APIView):
serializer_class = self.get_serializer_class()
context = self.get_serializer_context()
return serializer_class(instance, data=data, files=files,
- many=many, partial=partial, context=context)
+ many=many, partial=partial,
+ allow_add_remove=allow_add_remove,
+ context=context)
def get_pagination_serializer(self, page):
"""
@@ -121,11 +128,11 @@ class GenericAPIView(views.APIView):
deprecated_style = False
if page_size is not None:
warnings.warn('The `page_size` parameter to `paginate_queryset()` '
- 'is due to be deprecated. '
+ 'is deprecated. '
'Note that the return style of this method is also '
'changed, and will simply return a page object '
'when called without a `page_size` argument.',
- PendingDeprecationWarning, stacklevel=2)
+ DeprecationWarning, stacklevel=2)
deprecated_style = True
else:
# Determine the required page size.
@@ -136,10 +143,10 @@ class GenericAPIView(views.APIView):
if not self.allow_empty:
warnings.warn(
- 'The `allow_empty` parameter is due to be deprecated. '
+ 'The `allow_empty` parameter is deprecated. '
'To use `allow_empty=False` style behavior, You should override '
'`get_queryset()` and explicitly raise a 404 on empty querysets.',
- PendingDeprecationWarning, stacklevel=2
+ DeprecationWarning, stacklevel=2
)
paginator = self.paginator_class(queryset, page_size,
@@ -156,10 +163,11 @@ class GenericAPIView(views.APIView):
raise Http404(_("Page is not 'last', nor can it be converted to an int."))
try:
page = paginator.page(page_number)
- except InvalidPage as e:
- raise Http404(_('Invalid page (%(page_number)s): %(message)s') % {
- 'page_number': page_number,
- 'message': str(e)
+ except InvalidPage as exc:
+ error_format = _('Invalid page (%(page_number)s): %(message)s')
+ raise Http404(error_format % {
+ 'page_number': page_number,
+ 'message': str(exc)
})
if deprecated_style:
@@ -183,22 +191,27 @@ class GenericAPIView(views.APIView):
"""
Returns the list of filter backends that this view requires.
"""
- filter_backends = self.filter_backends or []
+ if self.filter_backends is None:
+ filter_backends = []
+ else:
+ # Note that we are returning a *copy* of the class attribute,
+ # so that it is safe for the view to mutate it if needed.
+ filter_backends = list(self.filter_backends)
+
if not filter_backends and self.filter_backend:
warnings.warn(
'The `filter_backend` attribute and `FILTER_BACKEND` setting '
- 'are due to be deprecated in favor of a `filter_backends` '
+ 'are deprecated in favor of a `filter_backends` '
'attribute and `DEFAULT_FILTER_BACKENDS` setting, that take '
'a *list* of filter backend classes.',
- PendingDeprecationWarning, stacklevel=2
+ DeprecationWarning, stacklevel=2
)
filter_backends = [self.filter_backend]
- return filter_backends
+ return filter_backends
- ########################
- ### The following methods provide default implementations
- ### that you may want to override for more complex cases.
+ # The following methods provide default implementations
+ # that you may want to override for more complex cases.
def get_paginate_by(self, queryset=None):
"""
@@ -211,8 +224,8 @@ class GenericAPIView(views.APIView):
"""
if queryset is not None:
warnings.warn('The `queryset` parameter to `get_paginate_by()` '
- 'is due to be deprecated.',
- PendingDeprecationWarning, stacklevel=2)
+ 'is deprecated.',
+ DeprecationWarning, stacklevel=2)
if self.paginate_by_param:
try:
@@ -256,6 +269,10 @@ class GenericAPIView(views.APIView):
This must be an iterable, and may be a queryset.
Defaults to using `self.queryset`.
+ This method should always be used rather than accessing `self.queryset`
+ directly, as `self.queryset` gets evaluated only once, and those results
+ are cached for all subsequent requests.
+
You may want to override this if you need to provide different
querysets depending on the incoming request.
@@ -267,8 +284,8 @@ class GenericAPIView(views.APIView):
if self.model is not None:
return self.model._default_manager.all()
- raise ImproperlyConfigured("'%s' must define 'queryset' or 'model'"
- % self.__class__.__name__)
+ error_format = "'%s' must define 'queryset' or 'model'"
+ raise ImproperlyConfigured(error_format % self.__class__.__name__)
def get_object(self, queryset=None):
"""
@@ -295,16 +312,16 @@ class GenericAPIView(views.APIView):
filter_kwargs = {self.lookup_field: lookup}
elif pk is not None and self.lookup_field == 'pk':
warnings.warn(
- 'The `pk_url_kwarg` attribute is due to be deprecated. '
+ 'The `pk_url_kwarg` attribute is deprecated. '
'Use the `lookup_field` attribute instead',
- PendingDeprecationWarning
+ DeprecationWarning
)
filter_kwargs = {'pk': pk}
elif slug is not None and self.lookup_field == 'pk':
warnings.warn(
- 'The `slug_url_kwarg` attribute is due to be deprecated. '
+ 'The `slug_url_kwarg` attribute is deprecated. '
'Use the `lookup_field` attribute instead',
- PendingDeprecationWarning
+ DeprecationWarning
)
filter_kwargs = {self.slug_field: slug}
else:
@@ -322,12 +339,11 @@ class GenericAPIView(views.APIView):
return obj
- ########################
- ### The following are placeholder methods,
- ### and are intended to be overridden.
- ###
- ### The are not called by GenericAPIView directly,
- ### but are used by the mixin methods.
+ # The following are placeholder methods,
+ # and are intended to be overridden.
+ #
+ # The are not called by GenericAPIView directly,
+ # but are used by the mixin methods.
def pre_save(self, obj):
"""
@@ -399,10 +415,8 @@ class GenericAPIView(views.APIView):
return ret
-##########################################################
-### Concrete view classes that provide method handlers ###
-### by composing the mixin classes with the base view. ###
-##########################################################
+# Concrete view classes that provide method handlers
+# by composing the mixin classes with the base view.
class CreateAPIView(mixins.CreateModelMixin,
GenericAPIView):
@@ -517,16 +531,14 @@ class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
return self.destroy(request, *args, **kwargs)
-##########################
-### Deprecated classes ###
-##########################
+# Deprecated classes
class MultipleObjectAPIView(GenericAPIView):
def __init__(self, *args, **kwargs):
warnings.warn(
- 'Subclassing `MultipleObjectAPIView` is due to be deprecated. '
+ 'Subclassing `MultipleObjectAPIView` is deprecated. '
'You should simply subclass `GenericAPIView` instead.',
- PendingDeprecationWarning, stacklevel=2
+ DeprecationWarning, stacklevel=2
)
super(MultipleObjectAPIView, self).__init__(*args, **kwargs)
@@ -534,8 +546,8 @@ class MultipleObjectAPIView(GenericAPIView):
class SingleObjectAPIView(GenericAPIView):
def __init__(self, *args, **kwargs):
warnings.warn(
- 'Subclassing `SingleObjectAPIView` is due to be deprecated. '
+ 'Subclassing `SingleObjectAPIView` is deprecated. '
'You should simply subclass `GenericAPIView` instead.',
- PendingDeprecationWarning, stacklevel=2
+ DeprecationWarning, stacklevel=2
)
super(SingleObjectAPIView, self).__init__(*args, **kwargs)