2013-04-04 23:00:44 +04:00
|
|
|
from functools import update_wrapper
|
|
|
|
from django.utils.decorators import classonlymethod
|
|
|
|
from rest_framework import views, generics, mixins
|
|
|
|
|
|
|
|
|
|
|
|
class ViewSetMixin(object):
|
|
|
|
"""
|
|
|
|
This is the magic.
|
|
|
|
|
|
|
|
Overrides `.as_view()` so that it takes an `actions` keyword that performs
|
|
|
|
the binding of HTTP methods to actions on the Resource.
|
|
|
|
|
|
|
|
For example, to create a concrete view binding the 'GET' and 'POST' methods
|
|
|
|
to the 'list' and 'create' actions...
|
|
|
|
|
|
|
|
view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
|
|
|
|
"""
|
2013-04-05 00:42:26 +04:00
|
|
|
_is_viewset = True
|
2013-04-04 23:00:44 +04:00
|
|
|
|
|
|
|
@classonlymethod
|
2013-04-05 00:42:26 +04:00
|
|
|
def as_view(cls, actions=None, name_suffix=None, **initkwargs):
|
2013-04-04 23:00:44 +04:00
|
|
|
"""
|
|
|
|
Main entry point for a request-response process.
|
|
|
|
|
|
|
|
Because of the way class based views create a closure around the
|
|
|
|
instantiated view, we need to totally reimplement `.as_view`,
|
|
|
|
and slightly modify the view function that is created and returned.
|
|
|
|
"""
|
|
|
|
# sanitize keyword arguments
|
|
|
|
for key in initkwargs:
|
|
|
|
if key in cls.http_method_names:
|
|
|
|
raise TypeError("You tried to pass in the %s method name as a "
|
|
|
|
"keyword argument to %s(). Don't do that."
|
|
|
|
% (key, cls.__name__))
|
|
|
|
if not hasattr(cls, key):
|
|
|
|
raise TypeError("%s() received an invalid keyword %r" % (
|
|
|
|
cls.__name__, key))
|
|
|
|
|
|
|
|
def view(request, *args, **kwargs):
|
|
|
|
self = cls(**initkwargs)
|
|
|
|
|
|
|
|
# Bind methods to actions
|
|
|
|
# This is the bit that's different to a standard view
|
|
|
|
for method, action in actions.items():
|
|
|
|
handler = getattr(self, action)
|
|
|
|
setattr(self, method, handler)
|
|
|
|
|
|
|
|
# Patch this in as it's otherwise only present from 1.5 onwards
|
|
|
|
if hasattr(self, 'get') and not hasattr(self, 'head'):
|
|
|
|
self.head = self.get
|
|
|
|
|
|
|
|
# And continue as usual
|
|
|
|
return self.dispatch(request, *args, **kwargs)
|
|
|
|
|
|
|
|
# take name and docstring from class
|
|
|
|
update_wrapper(view, cls, updated=())
|
|
|
|
|
|
|
|
# and possible attributes set by decorators
|
|
|
|
# like csrf_exempt from dispatch
|
|
|
|
update_wrapper(view, cls.dispatch, assigned=())
|
2013-04-05 00:42:26 +04:00
|
|
|
|
|
|
|
view.cls = cls
|
2013-04-04 23:00:44 +04:00
|
|
|
return view
|
|
|
|
|
|
|
|
|
|
|
|
class ViewSet(ViewSetMixin, views.APIView):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
# Note the inheritence of both MultipleObjectAPIView *and* SingleObjectAPIView
|
|
|
|
# is a bit weird given the diamond inheritence, but it will work for now.
|
|
|
|
# There's some implementation clean up that can happen later.
|
|
|
|
class ModelViewSet(mixins.CreateModelMixin,
|
|
|
|
mixins.RetrieveModelMixin,
|
|
|
|
mixins.UpdateModelMixin,
|
|
|
|
mixins.DestroyModelMixin,
|
|
|
|
mixins.ListModelMixin,
|
|
|
|
ViewSetMixin,
|
2013-04-09 22:37:19 +04:00
|
|
|
generics.GenericAPIView):
|
2013-04-04 23:00:44 +04:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
|
|
|
|
mixins.ListModelMixin,
|
|
|
|
ViewSetMixin,
|
2013-04-09 22:37:19 +04:00
|
|
|
generics.GenericAPIView):
|
2013-04-04 23:00:44 +04:00
|
|
|
pass
|