diff options
| author | Tom Christie | 2013-04-04 20:00:44 +0100 | 
|---|---|---|
| committer | Tom Christie | 2013-04-04 20:00:44 +0100 | 
| commit | c785628300d2b7cce63862a18915c537f8a3ab24 (patch) | |
| tree | 266aaf0f12ecb7228d50bffef671e8f611286f68 /rest_framework/viewsets.py | |
| parent | ec076a00786c6b89a55b6ffe2556bb3b777100f5 (diff) | |
| download | django-rest-framework-c785628300d2b7cce63862a18915c537f8a3ab24.tar.bz2 | |
Fleshing out viewsets/routers
Diffstat (limited to 'rest_framework/viewsets.py')
| -rw-r--r-- | rest_framework/viewsets.py | 119 | 
1 files changed, 86 insertions, 33 deletions
| diff --git a/rest_framework/viewsets.py b/rest_framework/viewsets.py index a5aef5b7..887a9722 100644 --- a/rest_framework/viewsets.py +++ b/rest_framework/viewsets.py @@ -1,33 +1,86 @@ -# Not properly implemented yet, just the basic idea - - -class BaseRouter(object): -    def __init__(self): -        self.resources = [] - -    def register(self, name, resource): -        self.resources.append((name, resource)) - -    @property -    def urlpatterns(self): -        ret = [] - -        for name, resource in self.resources: -            list_actions = { -                'get': getattr(resource, 'list', None), -                'post': getattr(resource, 'create', None) -            } -            detail_actions = { -                'get': getattr(resource, 'retrieve', None), -                'put': getattr(resource, 'update', None), -                'delete': getattr(resource, 'destroy', None) -            } -            list_regex = r'^%s/$' % name -            detail_regex = r'^%s/(?P<pk>[0-9]+)/$' % name -            list_name = '%s-list' -            detail_name = '%s-detail' - -            ret += url(list_regex, resource.as_view(list_actions), list_name) -            ret += url(detail_regex, resource.as_view(detail_actions), detail_name) - -        return ret +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'}) +    """ + +    @classonlymethod +    def as_view(cls, actions=None, **initkwargs): +        """ +        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=()) +        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, +                    generics.MultipleObjectAPIView, +                    generics.SingleObjectAPIView): +    pass + + +class ReadOnlyModelViewSet(mixins.RetrieveModelMixin, +                           mixins.ListModelMixin, +                           ViewSetMixin, +                           generics.MultipleObjectAPIView, +                           generics.SingleObjectAPIView): +    pass | 
