Fix up tests and examples after refactoring

This commit is contained in:
Tom Christie 2011-04-27 18:07:28 +01:00
parent 762a52edde
commit 028851bfa1
10 changed files with 36 additions and 34 deletions

View File

@ -74,3 +74,9 @@ class UserLoggedInAuthenticator(BaseAuthenticator):
return request.user return request.user
return None return None
#class DigestAuthentication(BaseAuthentication):
# pass
#
#class OAuthAuthentication(BaseAuthentication):
# pass

View File

@ -416,7 +416,7 @@ class RootModelResource(ModelResource):
queryset = self.queryset if self.queryset else self.model.objects.all() queryset = self.queryset if self.queryset else self.model.objects.all()
return queryset.filter(**kwargs) return queryset.filter(**kwargs)
put = delete = http_method_not_allowed put = delete = None
class QueryModelResource(ModelResource): class QueryModelResource(ModelResource):
"""Resource with default operations for list. """Resource with default operations for list.
@ -428,4 +428,4 @@ class QueryModelResource(ModelResource):
queryset = self.queryset if self.queryset else self.model.objects.all() queryset = self.queryset if self.queryset else self.model.objects.all()
return queryset.filer(**kwargs) return queryset.filer(**kwargs)
post = put = delete = http_method_not_allowed post = put = delete = None

View File

@ -41,7 +41,7 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View):
authenticators.BasicAuthenticator ) authenticators.BasicAuthenticator )
# List of all permissions required to access the resource # List of all permissions required to access the resource
permissions = ( permissions.DeleteMePermission, ) permissions = ()
# Optional form for input validation and presentation of HTML formatted responses. # Optional form for input validation and presentation of HTML formatted responses.
form = None form = None
@ -54,7 +54,7 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View):
@property @property
def allowed_methods(self): def allowed_methods(self):
return [method.upper() for method in self.http_method_names if hasattr(self, method)] return [method.upper() for method in self.http_method_names if getattr(self, method, None)]
def http_method_not_allowed(self, request, *args, **kwargs): def http_method_not_allowed(self, request, *args, **kwargs):
"""Return an HTTP 405 error if an operation is called which does not have a handler method.""" """Return an HTTP 405 error if an operation is called which does not have a handler method."""
@ -96,6 +96,9 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View):
# Get the appropriate handler method # Get the appropriate handler method
if self.method.lower() in self.http_method_names: if self.method.lower() in self.http_method_names:
handler = getattr(self, self.method.lower(), self.http_method_not_allowed) handler = getattr(self, self.method.lower(), self.http_method_not_allowed)
# If a previously defined method has been disabled
if handler is None:
handler = self.http_method_not_allowed
else: else:
handler = self.http_method_not_allowed handler = self.http_method_not_allowed
@ -125,3 +128,4 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View):
return self.emit(response) return self.emit(response)

View File

@ -7,11 +7,13 @@ from django.utils import simplejson as json
from djangorestframework.compat import RequestFactory from djangorestframework.compat import RequestFactory
from djangorestframework.resource import Resource from djangorestframework.resource import Resource
from djangorestframework import permissions
import base64 import base64
class MockResource(Resource): class MockResource(Resource):
permissions = ( permissions.IsAuthenticated, )
def post(self, request): def post(self, request):
return {'a':1, 'b':2, 'c':3} return {'a':1, 'b':2, 'c':3}

View File

@ -8,25 +8,21 @@ MAX_POSTS = 10
class BlogPosts(RootModelResource): class BlogPosts(RootModelResource):
"""A resource with which lists all existing blog posts and creates new blog posts.""" """A resource with which lists all existing blog posts and creates new blog posts."""
anon_allowed_methods = allowed_methods = ('GET', 'POST',)
model = models.BlogPost model = models.BlogPost
fields = BLOG_POST_FIELDS fields = BLOG_POST_FIELDS
class BlogPostInstance(ModelResource): class BlogPostInstance(ModelResource):
"""A resource which represents a single blog post.""" """A resource which represents a single blog post."""
anon_allowed_methods = allowed_methods = ('GET', 'PUT', 'DELETE')
model = models.BlogPost model = models.BlogPost
fields = BLOG_POST_FIELDS fields = BLOG_POST_FIELDS
class Comments(RootModelResource): class Comments(RootModelResource):
"""A resource which lists all existing comments for a given blog post, and creates new blog comments for a given blog post.""" """A resource which lists all existing comments for a given blog post, and creates new blog comments for a given blog post."""
anon_allowed_methods = allowed_methods = ('GET', 'POST',)
model = models.Comment model = models.Comment
fields = COMMENT_FIELDS fields = COMMENT_FIELDS
class CommentInstance(ModelResource): class CommentInstance(ModelResource):
"""A resource which represents a single comment.""" """A resource which represents a single comment."""
anon_allowed_methods = allowed_methods = ('GET', 'PUT', 'DELETE')
model = models.Comment model = models.Comment
fields = COMMENT_FIELDS fields = COMMENT_FIELDS

View File

@ -1,12 +1,13 @@
from djangorestframework.compat import View # Use Django 1.3's django.views.generic.View, or fall back to a clone of that if Django < 1.3 from djangorestframework.compat import View # Use Django 1.3's django.views.generic.View, or fall back to a clone of that if Django < 1.3
from djangorestframework.emitters import EmitterMixin, DEFAULT_EMITTERS from djangorestframework.mixins import ResponseMixin
from djangorestframework.emitters import DEFAULT_EMITTERS
from djangorestframework.response import Response from djangorestframework.response import Response
from django.conf.urls.defaults import patterns, url from django.conf.urls.defaults import patterns, url
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
class ExampleView(EmitterMixin, View): class ExampleView(ResponseMixin, View):
"""An example view using Django 1.3's class based views. """An example view using Django 1.3's class based views.
Uses djangorestframework's EmitterMixin to provide support for multiple output formats.""" Uses djangorestframework's EmitterMixin to provide support for multiple output formats."""
emitters = DEFAULT_EMITTERS emitters = DEFAULT_EMITTERS

View File

@ -7,12 +7,10 @@ class MyModelRootResource(RootModelResource):
"""A create/list resource for MyModel. """A create/list resource for MyModel.
Available for both authenticated and anonymous access for the purposes of the sandbox.""" Available for both authenticated and anonymous access for the purposes of the sandbox."""
model = MyModel model = MyModel
allowed_methods = anon_allowed_methods = ('GET', 'POST')
fields = FIELDS fields = FIELDS
class MyModelResource(ModelResource): class MyModelResource(ModelResource):
"""A read/update/delete resource for MyModel. """A read/update/delete resource for MyModel.
Available for both authenticated and anonymous access for the purposes of the sandbox.""" Available for both authenticated and anonymous access for the purposes of the sandbox."""
model = MyModel model = MyModel
allowed_methods = anon_allowed_methods = ('GET', 'PUT', 'DELETE')
fields = FIELDS fields = FIELDS

View File

@ -41,26 +41,25 @@ class PygmentsRoot(Resource):
"""This example demonstrates a simple RESTful Web API aound the awesome pygments library. """This example demonstrates a simple RESTful Web API aound the awesome pygments library.
This top level resource is used to create highlighted code snippets, and to list all the existing code snippets.""" This top level resource is used to create highlighted code snippets, and to list all the existing code snippets."""
form = PygmentsForm form = PygmentsForm
allowed_methods = anon_allowed_methods = ('GET', 'POST',)
def get(self, request, auth): def get(self, request):
"""Return a list of all currently existing snippets.""" """Return a list of all currently existing snippets."""
unique_ids = [os.path.split(f)[1] for f in list_dir_sorted_by_ctime(HIGHLIGHTED_CODE_DIR)] unique_ids = [os.path.split(f)[1] for f in list_dir_sorted_by_ctime(HIGHLIGHTED_CODE_DIR)]
return [reverse('pygments-instance', args=[unique_id]) for unique_id in unique_ids] return [reverse('pygments-instance', args=[unique_id]) for unique_id in unique_ids]
def post(self, request, auth, content): def post(self, request):
"""Create a new highlighed snippet and return it's location. """Create a new highlighed snippet and return it's location.
For the purposes of the sandbox example, also ensure we delete the oldest snippets if we have > MAX_FILES.""" For the purposes of the sandbox example, also ensure we delete the oldest snippets if we have > MAX_FILES."""
unique_id = str(uuid.uuid1()) unique_id = str(uuid.uuid1())
pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id) pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id)
lexer = get_lexer_by_name(content['lexer']) lexer = get_lexer_by_name(self.CONTENT['lexer'])
linenos = 'table' if content['linenos'] else False linenos = 'table' if self.CONTENT['linenos'] else False
options = {'title': content['title']} if content['title'] else {} options = {'title': self.CONTENT['title']} if self.CONTENT['title'] else {}
formatter = HtmlFormatter(style=content['style'], linenos=linenos, full=True, **options) formatter = HtmlFormatter(style=self.CONTENT['style'], linenos=linenos, full=True, **options)
with open(pathname, 'w') as outfile: with open(pathname, 'w') as outfile:
highlight(content['code'], lexer, formatter, outfile) highlight(self.CONTENT['code'], lexer, formatter, outfile)
remove_oldest_files(HIGHLIGHTED_CODE_DIR, MAX_FILES) remove_oldest_files(HIGHLIGHTED_CODE_DIR, MAX_FILES)
@ -70,20 +69,19 @@ class PygmentsRoot(Resource):
class PygmentsInstance(Resource): class PygmentsInstance(Resource):
"""Simply return the stored highlighted HTML file with the correct mime type. """Simply return the stored highlighted HTML file with the correct mime type.
This Resource only emits HTML and uses a standard HTML emitter rather than the emitters.DocumentingHTMLEmitter class.""" This Resource only emits HTML and uses a standard HTML emitter rather than the emitters.DocumentingHTMLEmitter class."""
allowed_methods = anon_allowed_methods = ('GET',)
emitters = (HTMLEmitter,) emitters = (HTMLEmitter,)
def get(self, request, auth, unique_id): def get(self, request, unique_id):
"""Return the highlighted snippet.""" """Return the highlighted snippet."""
pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id) pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id)
if not os.path.exists(pathname): if not os.path.exists(pathname):
return Resource(status.HTTP_404_NOT_FOUND) return Response(status.HTTP_404_NOT_FOUND)
return open(pathname, 'r').read() return open(pathname, 'r').read()
def delete(self, request, auth, unique_id): def delete(self, request, unique_id):
"""Delete the highlighted snippet.""" """Delete the highlighted snippet."""
pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id) pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id)
if not os.path.exists(pathname): if not os.path.exists(pathname):
return Resource(status.HTTP_404_NOT_FOUND) return Response(status.HTTP_404_NOT_FOUND)
return os.remove(pathname) return os.remove(pathname)

View File

@ -8,24 +8,22 @@ from resourceexample.forms import MyForm
class ExampleResource(Resource): class ExampleResource(Resource):
"""A basic read-only resource that points to 3 other resources.""" """A basic read-only resource that points to 3 other resources."""
allowed_methods = anon_allowed_methods = ('GET',)
def get(self, request, auth): def get(self, request):
return {"Some other resources": [reverse('another-example-resource', kwargs={'num':num}) for num in range(3)]} return {"Some other resources": [reverse('another-example-resource', kwargs={'num':num}) for num in range(3)]}
class AnotherExampleResource(Resource): class AnotherExampleResource(Resource):
"""A basic GET-able/POST-able resource.""" """A basic GET-able/POST-able resource."""
allowed_methods = anon_allowed_methods = ('GET', 'POST')
form = MyForm # Optional form validation on input (Applies in this case the POST method, but can also apply to PUT) form = MyForm # Optional form validation on input (Applies in this case the POST method, but can also apply to PUT)
def get(self, request, auth, num): def get(self, request, num):
"""Handle GET requests""" """Handle GET requests"""
if int(num) > 2: if int(num) > 2:
return Response(status.HTTP_404_NOT_FOUND) return Response(status.HTTP_404_NOT_FOUND)
return "GET request to AnotherExampleResource %s" % num return "GET request to AnotherExampleResource %s" % num
def post(self, request, auth, content, num): def post(self, request, num):
"""Handle POST requests""" """Handle POST requests"""
if int(num) > 2: if int(num) > 2:
return Response(status.HTTP_404_NOT_FOUND) return Response(status.HTTP_404_NOT_FOUND)
return "POST request to AnotherExampleResource %s, with content: %s" % (num, repr(content)) return "POST request to AnotherExampleResource %s, with content: %s" % (num, repr(self.CONTENT))

View File

@ -24,9 +24,8 @@ class Sandbox(Resource):
6. A blog posts and comments API. 6. A blog posts and comments API.
Please feel free to browse, create, edit and delete the resources in these examples.""" Please feel free to browse, create, edit and delete the resources in these examples."""
allowed_methods = anon_allowed_methods = ('GET',)
def get(self, request, auth): def get(self, request):
return [{'name': 'Simple Resource example', 'url': reverse('example-resource')}, return [{'name': 'Simple Resource example', 'url': reverse('example-resource')},
{'name': 'Simple ModelResource example', 'url': reverse('my-model-root-resource')}, {'name': 'Simple ModelResource example', 'url': reverse('my-model-root-resource')},
{'name': 'Simple Mixin-only example', 'url': reverse('mixin-view')}, {'name': 'Simple Mixin-only example', 'url': reverse('mixin-view')},