From f79ed6175df62f68dba9179f792f95b6ac6dca14 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 8 Oct 2012 14:13:15 +0100 Subject: [PATCH] Add RetrieveDestroyAPIView and remove Metadata mixin --- docs/api-guide/generic-views.md | 29 +++++++++++++++++++++++++---- rest_framework/generics.py | 27 ++++++++++++--------------- rest_framework/mixins.py | 25 ------------------------- rest_framework/views.py | 23 +++++++++++++++++++++++ 4 files changed, 60 insertions(+), 44 deletions(-) diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md index 571cc66f2..8bf7a7e2b 100644 --- a/docs/api-guide/generic-views.md +++ b/docs/api-guide/generic-views.md @@ -47,9 +47,11 @@ For very simple cases you might want to pass through any class attributes using # API Reference +The following classes are the concrete generic views. If you're using generic views this is normally the level you'll be working at unless you need heavily customized behavior. + ## ListAPIView -Used for read-only endpoints to represent a collection of model instances. +Used for **read-only** endpoints to represent a **collection of model instances**. Provides a `get` method handler. @@ -57,7 +59,7 @@ Extends: [MultipleObjectBaseAPIView], [ListModelMixin] ## ListCreateAPIView -Used for read-write endpoints to represent a collection of model instances. +Used for **read-write** endpoints to represent a **collection of model instances**. Provides `get` and `post` method handlers. @@ -65,15 +67,23 @@ Extends: [MultipleObjectBaseAPIView], [ListModelMixin], [CreateModelMixin] ## RetrieveAPIView -Used for read-only endpoints to represent a single model instance. +Used for **read-only** endpoints to represent a **single model instance**. Provides a `get` method handler. Extends: [SingleObjectBaseAPIView], [RetrieveModelMixin] +## RetrieveDestroyAPIView + +Used for **read or delete** endpoints to represent a **single model instance**. + +Provides `get` and `delete` method handlers. + +Extends: [SingleObjectBaseAPIView], [RetrieveModelMixin], [DestroyModelMixin] + ## RetrieveUpdateDestroyAPIView -Used for read-write endpoints to represent a single model instance. +Used for **read-write** endpoints to represent a **single model instance**. Provides `get`, `put` and `delete` method handlers. @@ -111,28 +121,39 @@ The mixin classes provide the actions that are used to provide the basic view be Provides a `.list(request, *args, **kwargs)` method, that implements listing a queryset. +Should be mixed in with [MultipleObjectBaseAPIView]. + ## CreateModelMixin Provides a `.create(request, *args, **kwargs)` method, that implements creating and saving a new model instance. +Should be mixed in with any [BaseAPIView]. + ## RetrieveModelMixin Provides a `.retrieve(request, *args, **kwargs)` method, that implements returning an existing model instance in a response. +Should be mixed in with [SingleObjectBaseAPIView]. + ## UpdateModelMixin Provides a `.update(request, *args, **kwargs)` method, that implements updating and saving an existing model instance. +Should be mixed in with [SingleObjectBaseAPIView]. + ## DestroyModelMixin Provides a `.destroy(request, *args, **kwargs)` method, that implements deletion of an existing model instance. +Should be mixed in with [SingleObjectBaseAPIView]. + [cite]: https://docs.djangoproject.com/en/dev/ref/class-based-views/#base-vs-generic-views [MultipleObjectMixin]: https://docs.djangoproject.com/en/dev/ref/class-based-views/mixins-multiple-object/ [SingleObjectMixin]: https://docs.djangoproject.com/en/dev/ref/class-based-views/mixins-single-object/ [multiple-object-mixin-classy]: http://ccbv.co.uk/projects/Django/1.4/django.views.generic.list/MultipleObjectMixin/ [single-object-mixin-classy]: http://ccbv.co.uk/projects/Django/1.4/django.views.generic.detail/SingleObjectMixin/ +[BaseAPIView]: #baseapiview [SingleObjectBaseAPIView]: #singleobjectbaseapiview [MultipleObjectBaseAPIView]: #multipleobjectbaseapiview [ListModelMixin]: #listmodelmixin diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 51874f288..59739d010 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -96,7 +96,6 @@ class SingleObjectBaseView(SingleObjectMixin, BaseView): ### by composing the mixin classes with a base view. ### class ListAPIView(mixins.ListModelMixin, - mixins.MetadataMixin, MultipleObjectBaseView): """ Concrete view for listing a queryset. @@ -104,13 +103,9 @@ class ListAPIView(mixins.ListModelMixin, def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) - def options(self, request, *args, **kwargs): - return self.metadata(request, *args, **kwargs) - class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, - mixins.MetadataMixin, MultipleObjectBaseView): """ Concrete view for listing a queryset or creating a model instance. @@ -121,12 +116,8 @@ class ListCreateAPIView(mixins.ListModelMixin, def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) - def options(self, request, *args, **kwargs): - return self.metadata(request, *args, **kwargs) - class RetrieveAPIView(mixins.RetrieveModelMixin, - mixins.MetadataMixin, SingleObjectBaseView): """ Concrete view for retrieving a model instance. @@ -134,14 +125,23 @@ class RetrieveAPIView(mixins.RetrieveModelMixin, def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) - def options(self, request, *args, **kwargs): - return self.metadata(request, *args, **kwargs) + +class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, + mixins.DestroyModelMixin, + SingleObjectBaseView): + """ + Concrete view for retrieving or deleting a model instance. + """ + def get(self, request, *args, **kwargs): + return self.retrieve(request, *args, **kwargs) + + def delete(self, request, *args, **kwargs): + return self.destroy(request, *args, **kwargs) class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, - mixins.MetadataMixin, SingleObjectBaseView): """ Concrete view for retrieving, updating or deleting a model instance. @@ -154,6 +154,3 @@ class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs) - - def options(self, request, *args, **kwargs): - return self.metadata(request, *args, **kwargs) diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py index 7cfbe0302..29153e182 100644 --- a/rest_framework/mixins.py +++ b/rest_framework/mixins.py @@ -112,28 +112,3 @@ class DestroyModelMixin(object): self.object = self.get_object() self.object.delete() return Response(status=status.HTTP_204_NO_CONTENT) - - -# TODO: Remove MetadataMixin, and implement on APIView.options() -class MetadataMixin(object): - """ - Return a dicitonary of view metadata. - Should be mixed in with any `BaseView`. - - This mixin is typically used for the HTTP 'OPTIONS' method. - """ - def metadata(self, request, *args, **kwargs): - content = { - 'name': self.get_name(), - 'description': self.get_description(), - 'renders': [renderer.media_type for renderer in self.renderer_classes], - 'parses': [parser.media_type for parser in self.parser_classes], - } - # TODO: Add 'fields', from serializer info. - # serializer = self.get_serializer() - # if serializer is not None: - # field_name_types = {} - # for name, field in form.fields.iteritems(): - # field_name_types[name] = field.__class__.__name__ - # content['fields'] = field_name_types - return Response(content, status=status.HTTP_200_OK) diff --git a/rest_framework/views.py b/rest_framework/views.py index 0aa1dd0d8..790c76faf 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -124,6 +124,21 @@ class APIView(View): description = escape(description).replace('\n', '
') return mark_safe(description) + def metadata(self, request): + return { + 'name': self.get_name(), + 'description': self.get_description(), + 'renders': [renderer.media_type for renderer in self.renderer_classes], + 'parses': [parser.media_type for parser in self.parser_classes], + } + # TODO: Add 'fields', from serializer info, if it exists. + # serializer = self.get_serializer() + # if serializer is not None: + # field_name_types = {} + # for name, field in form.fields.iteritems(): + # field_name_types[name] = field.__class__.__name__ + # content['fields'] = field_name_types + def http_method_not_allowed(self, request, *args, **kwargs): """ Called if `request.method` does not corrospond to a handler method. @@ -309,3 +324,11 @@ class APIView(View): self.response = self.finalize_response(request, response, *args, **kwargs) return self.response + + def options(self, request, *args, **kwargs): + """ + Handler method for HTTP 'OPTIONS' request. + We may as well implement this as Django will otherwise provide + a less useful default implementation. + """ + return Response(self.metadata(request), status=status.HTTP_200_OK)