From 195006bbc36c21f0154fe1ab7c46f339b2efe559 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 26 Oct 2012 09:27:59 +0100 Subject: [PATCH] Drop resources from codebase since implementation is only partial (Created resoorces-routers branch for future reference) --- .../6-resource-orientated-projects.md | 76 --------------- rest_framework/resources.py | 96 ------------------- 2 files changed, 172 deletions(-) delete mode 100644 docs/tutorial/6-resource-orientated-projects.md delete mode 100644 rest_framework/resources.py diff --git a/docs/tutorial/6-resource-orientated-projects.md b/docs/tutorial/6-resource-orientated-projects.md deleted file mode 100644 index 9ee599ae3..000000000 --- a/docs/tutorial/6-resource-orientated-projects.md +++ /dev/null @@ -1,76 +0,0 @@ -# Tutorial 6 - Resources - -Resource classes are just View classes that don't have any handler methods bound to them. The actions on a resource are defined, - -This allows us to: - -* Encapsulate common behaviour across a class of views, in a single Resource class. -* Separate out the actions of a Resource from the specifics of how those actions should be bound to a particular set of URLs. - -## Refactoring to use Resources, not Views - -For instance, we can re-write our 4 sets of views into something more compact... - -resources.py - - class BlogPostResource(ModelResource): - serializer_class = BlogPostSerializer - model = BlogPost - permissions_classes = (permissions.IsAuthenticatedOrReadOnly,) - throttle_classes = (throttles.UserRateThrottle,) - - class CommentResource(ModelResource): - serializer_class = CommentSerializer - model = Comment - permissions_classes = (permissions.IsAuthenticatedOrReadOnly,) - throttle_classes = (throttles.UserRateThrottle,) - -## Binding Resources to URLs explicitly -The handler methods only get bound to the actions when we define the URLConf. Here's our urls.py: - - comment_root = CommentResource.as_view(actions={ - 'get': 'list', - 'post': 'create' - }) - comment_instance = CommentInstance.as_view(actions={ - 'get': 'retrieve', - 'put': 'update', - 'delete': 'destroy' - }) - ... # And for blog post - - urlpatterns = patterns('blogpost.views', - url(r'^$', comment_root), - url(r'^(?P[0-9]+)$', comment_instance) - ... # And for blog post - ) - -## Using Routers - -Right now that hasn't really saved us a lot of code. However, now that we're using Resources rather than Views, we actually don't need to design the urlconf ourselves. The conventions for wiring up resources into views and urls can be handled automatically, using `Router` classes. All we need to do is register the appropriate resources with a router, and let it do the rest. Here's our re-wired `urls.py` file. - - from blog import resources - from rest_framework.routers import DefaultRouter - - router = DefaultRouter() - router.register(resources.BlogPostResource) - router.register(resources.CommentResource) - urlpatterns = router.urlpatterns - -## Trade-offs between views vs resources. - -Writing resource-oriented code can be a good thing. It helps ensure that URL conventions will be consistent across your APIs, and minimises the amount of code you need to write. - -The trade-off is that the behaviour is less explict. It can be more difficult to determine what code path is being followed, or where to override some behaviour. - -## Onwards and upwards. - -We've reached the end of our tutorial. If you want to get more involved in the REST framework project, here's a few places you can start: - -* Contribute on GitHub by reviewing issues, and submitting issues or pull requests. -* Join the REST framework group, and help build the community. -* Follow me [on Twitter][twitter] and say hi. - -**Now go build some awesome things.** - -[twitter]: https://twitter.com/_tomchristie diff --git a/rest_framework/resources.py b/rest_framework/resources.py deleted file mode 100644 index dd8a54716..000000000 --- a/rest_framework/resources.py +++ /dev/null @@ -1,96 +0,0 @@ -##### RESOURCES AND ROUTERS ARE NOT YET IMPLEMENTED - PLACEHOLDER ONLY ##### - -from functools import update_wrapper -import inspect -from django.utils.decorators import classonlymethod -from rest_framework import views, generics - - -def wrapped(source, dest): - """ - Copy public, non-method attributes from source to dest, and return dest. - """ - for attr in [attr for attr in dir(source) - if not attr.startswith('_') and not inspect.ismethod(attr)]: - setattr(dest, attr, getattr(source, attr)) - return dest - - -##### RESOURCES AND ROUTERS ARE NOT YET IMPLEMENTED - PLACEHOLDER ONLY ##### - -class ResourceMixin(object): - """ - Clone Django's `View.as_view()` behaviour *except* using REST framework's - 'method -> action' binding for resources. - """ - - @classonlymethod - def as_view(cls, actions, **initkwargs): - """ - Main entry point for a request-response process. - """ - # 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 - for method, action in actions.items(): - handler = getattr(self, action) - setattr(self, method, handler) - - # As you were, solider. - if hasattr(self, 'get') and not hasattr(self, 'head'): - self.head = self.get - 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 - - -##### RESOURCES AND ROUTERS ARE NOT YET IMPLEMENTED - PLACEHOLDER ONLY ##### - -class Resource(ResourceMixin, views.APIView): - pass - - -##### RESOURCES AND ROUTERS ARE NOT YET IMPLEMENTED - PLACEHOLDER ONLY ##### - -class ModelResource(ResourceMixin, views.APIView): - # TODO: Actually delegation won't work - root_class = generics.ListCreateAPIView - detail_class = generics.RetrieveUpdateDestroyAPIView - - def root_view(self): - return wrapped(self, self.root_class()) - - def detail_view(self): - return wrapped(self, self.detail_class()) - - def list(self, request, *args, **kwargs): - return self.root_view().list(request, args, kwargs) - - def create(self, request, *args, **kwargs): - return self.root_view().create(request, args, kwargs) - - def retrieve(self, request, *args, **kwargs): - return self.detail_view().retrieve(request, args, kwargs) - - def update(self, request, *args, **kwargs): - return self.detail_view().update(request, args, kwargs) - - def destroy(self, request, *args, **kwargs): - return self.detail_view().destroy(request, args, kwargs)