First pass at mixins & generic views

This commit is contained in:
Tom Christie 2012-09-03 17:49:22 +01:00
parent a092a72844
commit 6e21915934
3 changed files with 162 additions and 17 deletions

View File

@ -0,0 +1,64 @@
from djangorestframework import status
from djangorestframework.response import Response
class CreateModelMixin(object):
"""
Create a model instance.
Should be mixed in with any `APIView`
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.DATA)
if serializer.is_valid():
self.object = serializer.object
self.object.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.error_data, status=status.HTTP_400_BAD_REQUEST)
class ListModelMixin(object):
"""
List a queryset.
Should be mixed in with `MultipleObjectBaseView`.
"""
def list(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
serializer = self.get_serializer(instance=self.object_list)
return Response(serializer.data)
class RetrieveModelMixin(object):
"""
Retrieve a model instance.
Should be mixed in with `SingleObjectBaseView`.
"""
def retrieve(self, request, *args, **kwargs):
self.object = self.get_object()
serializer = self.get_serializer(instance=self.object)
return Response(serializer.data)
class UpdateModelMixin(object):
"""
Update a model instance.
Should be mixed in with `SingleObjectBaseView`.
"""
def update(self, request, *args, **kwargs):
self.object = self.get_object()
serializer = self.get_serializer(data=request.DATA, instance=self.object)
if serializer.is_valid():
self.object = serializer.deserialized
self.object.save()
return Response(serializer.data)
return Response(serializer.error_data, status=status.HTTP_400_BAD_REQUEST)
class DestroyModelMixin(object):
"""
Destroy a model instance.
Should be mixed in with `SingleObjectBaseView`.
"""
def destroy(self, request, *args, **kwargs):
self.object = self.get_object()
self.object.delete()
return Response(status=status.HTTP_204_NO_CONTENT)

View File

@ -11,12 +11,14 @@ from django.http import Http404
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.views.decorators.csrf import csrf_exempt
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.list import MultipleObjectMixin
from djangorestframework.compat import View as _View, apply_markdown
from djangorestframework.response import Response
from djangorestframework.request import Request
from djangorestframework.settings import api_settings
from djangorestframework import parsers, authentication, permissions, status, exceptions
from djangorestframework import parsers, authentication, permissions, status, exceptions, mixins
__all__ = (
@ -281,3 +283,71 @@ class APIView(_View):
field_name_types[name] = field.__class__.__name__
content['fields'] = field_name_types
raise Response(content, status=status.HTTP_200_OK)
# TODO: .get_serializer()
### Abstract view classes, that do not provide any method handlers ###
class MultipleObjectBaseView(MultipleObjectMixin, APIView):
"""
Base class for views onto a queryset.
"""
pass
class SingleObjectBaseView(SingleObjectMixin, APIView):
"""
Base class for views onto a model instance.
"""
pass
### Concrete view classes, that provide existing method handlers ###
class ListAPIView(mixins.ListModelMixin,
MultipleObjectBaseView):
"""
Concrete view for listing a queryset.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class RootAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
MultipleObjectBaseView):
"""
Concrete view for listing a queryset or creating a model instance.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class DetailAPIView(mixins.RetrieveModelMixin,
SingleObjectBaseView):
"""
Concrete view for retrieving a model instance.
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
class InstanceAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
SingleObjectBaseView):
"""
Concrete view for retrieving, updating or deleting a model instance.
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)

View File

@ -57,7 +57,7 @@ So far, so good. It looks pretty similar to the previous case, but we've got be
comment = serializer.deserialized
comment.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return Response(serializer.error_data, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
comment = self.get_object(pk)
@ -79,27 +79,38 @@ We can compose those mixin classes, to recreate our existing API behaviour with
from blog.models import Comment
from blog.serializers import CommentSerializer
from djangorestframework import mixins, views
from djangorestframework import mixins
from djangorestframework import views
class CommentRoot(mixins.ListModelQuerysetMixin,
mixins.CreateModelInstanceMixin,
views.BaseRootAPIView):
class CommentRoot(mixins.ListModelMixin,
mixins.CreateModelMixin,
views.MultipleObjectBaseView):
model = Comment
serializer_class = CommentSerializer
get = list
post = create
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class CommentInstance(mixins.RetrieveModelInstanceMixin,
mixins.UpdateModelInstanceMixin,
mixins.DestroyModelInstanceMixin,
views.BaseInstanceAPIView):
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class CommentInstance(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
views.SingleObjectBaseView):
model = Comment
serializer_class = CommentSerializer
get = retrieve
put = update
delete = destroy
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
## Reusing generic class based views
@ -109,11 +120,11 @@ That's a lot less code than before, but we can go one step further still. REST
from blog.serializers import CommentSerializer
from djangorestframework import views
class CommentRoot(views.RootAPIView):
class CommentRoot(views.RootModelView):
model = Comment
serializer_class = CommentSerializer
class CommentInstance(views.InstanceAPIView):
class CommentInstance(views.InstanceModelView):
model = Comment
serializer_class = CommentSerializer