aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/blogpost/models.py3
-rw-r--r--examples/blogpost/resources.py27
-rw-r--r--examples/blogpost/tests.py164
-rw-r--r--examples/blogpost/urls.py29
-rw-r--r--examples/modelresourceexample/resources.py7
-rw-r--r--examples/modelresourceexample/urls.py10
-rw-r--r--examples/permissionsexample/__init__.py (renamed from examples/modelresourceexample/views.py)0
-rw-r--r--examples/permissionsexample/urls.py6
-rw-r--r--examples/permissionsexample/views.py20
-rw-r--r--examples/pygments_api/views.py11
-rw-r--r--examples/resourceexample/urls.py6
-rw-r--r--examples/resourceexample/views.py33
-rw-r--r--examples/sandbox/views.py4
-rw-r--r--examples/urls.py1
14 files changed, 177 insertions, 144 deletions
diff --git a/examples/blogpost/models.py b/examples/blogpost/models.py
index c4925a15..d77f530d 100644
--- a/examples/blogpost/models.py
+++ b/examples/blogpost/models.py
@@ -22,6 +22,9 @@ class BlogPost(models.Model):
slug = models.SlugField(editable=False, default='')
def save(self, *args, **kwargs):
+ """
+ For the purposes of the sandbox, limit the maximum number of stored models.
+ """
self.slug = slugify(self.title)
super(self.__class__, self).save(*args, **kwargs)
for obj in self.__class__.objects.order_by('-created')[MAX_POSTS:]:
diff --git a/examples/blogpost/resources.py b/examples/blogpost/resources.py
new file mode 100644
index 00000000..9b91ed73
--- /dev/null
+++ b/examples/blogpost/resources.py
@@ -0,0 +1,27 @@
+from django.core.urlresolvers import reverse
+from djangorestframework.resources import ModelResource
+from blogpost.models import BlogPost, Comment
+
+
+class BlogPostResource(ModelResource):
+ """
+ A Blog Post has a *title* and *content*, and can be associated with zero or more comments.
+ """
+ model = BlogPost
+ fields = ('created', 'title', 'slug', 'content', 'url', 'comments')
+ ordering = ('-created',)
+
+ def comments(self, instance):
+ return reverse('comments', kwargs={'blogpost': instance.key})
+
+
+class CommentResource(ModelResource):
+ """
+ A Comment is associated with a given Blog Post and has a *username* and *comment*, and optionally a *rating*.
+ """
+ model = Comment
+ fields = ('username', 'comment', 'created', 'rating', 'url', 'blogpost')
+ ordering = ('-created',)
+
+ def blogpost(self, instance):
+ return reverse('blog-post', kwargs={'key': instance.blogpost.key}) \ No newline at end of file
diff --git a/examples/blogpost/tests.py b/examples/blogpost/tests.py
index 9b9a682f..e55f0f90 100644
--- a/examples/blogpost/tests.py
+++ b/examples/blogpost/tests.py
@@ -7,79 +7,80 @@ from django.core.urlresolvers import reverse
from django.utils import simplejson as json
from djangorestframework.compat import RequestFactory
-
-from blogpost import views, models
-import blogpost
-
-
-class AcceptHeaderTests(TestCase):
- """Test correct behaviour of the Accept header as specified by RFC 2616:
-
- http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1"""
-
- def assert_accept_mimetype(self, mimetype, expect=None):
- """Assert that a request with given mimetype in the accept header,
- gives a response with the appropriate content-type."""
- if expect is None:
- expect = mimetype
-
- resp = self.client.get(reverse(views.RootResource), HTTP_ACCEPT=mimetype)
-
- self.assertEquals(resp['content-type'], expect)
-
-
- def dont_test_accept_json(self):
- """Ensure server responds with Content-Type of JSON when requested."""
- self.assert_accept_mimetype('application/json')
-
- def dont_test_accept_xml(self):
- """Ensure server responds with Content-Type of XML when requested."""
- self.assert_accept_mimetype('application/xml')
-
- def dont_test_accept_json_when_prefered_to_xml(self):
- """Ensure server responds with Content-Type of JSON when it is the client's prefered choice."""
- self.assert_accept_mimetype('application/json;q=0.9, application/xml;q=0.1', expect='application/json')
-
- def dont_test_accept_xml_when_prefered_to_json(self):
- """Ensure server responds with Content-Type of XML when it is the client's prefered choice."""
- self.assert_accept_mimetype('application/json;q=0.1, application/xml;q=0.9', expect='application/xml')
-
- def dont_test_default_json_prefered(self):
- """Ensure server responds with JSON in preference to XML."""
- self.assert_accept_mimetype('application/json,application/xml', expect='application/json')
-
- def dont_test_accept_generic_subtype_format(self):
- """Ensure server responds with an appropriate type, when the subtype is left generic."""
- self.assert_accept_mimetype('text/*', expect='text/html')
-
- def dont_test_accept_generic_type_format(self):
- """Ensure server responds with an appropriate type, when the type and subtype are left generic."""
- self.assert_accept_mimetype('*/*', expect='application/json')
-
- def dont_test_invalid_accept_header_returns_406(self):
- """Ensure server returns a 406 (not acceptable) response if we set the Accept header to junk."""
- resp = self.client.get(reverse(views.RootResource), HTTP_ACCEPT='invalid/invalid')
- self.assertNotEquals(resp['content-type'], 'invalid/invalid')
- self.assertEquals(resp.status_code, 406)
-
- def dont_test_prefer_specific_over_generic(self): # This test is broken right now
- """More specific accept types have precedence over less specific types."""
- self.assert_accept_mimetype('application/xml, */*', expect='application/xml')
- self.assert_accept_mimetype('*/*, application/xml', expect='application/xml')
-
-
-class AllowedMethodsTests(TestCase):
- """Basic tests to check that only allowed operations may be performed on a Resource"""
-
- def dont_test_reading_a_read_only_resource_is_allowed(self):
- """GET requests on a read only resource should default to a 200 (OK) response"""
- resp = self.client.get(reverse(views.RootResource))
- self.assertEquals(resp.status_code, 200)
-
- def dont_test_writing_to_read_only_resource_is_not_allowed(self):
- """PUT requests on a read only resource should default to a 405 (method not allowed) response"""
- resp = self.client.put(reverse(views.RootResource), {})
- self.assertEquals(resp.status_code, 405)
+from djangorestframework.views import InstanceModelView, ListOrCreateModelView
+
+from blogpost import models, urls
+#import blogpost
+
+
+# class AcceptHeaderTests(TestCase):
+# """Test correct behaviour of the Accept header as specified by RFC 2616:
+#
+# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1"""
+#
+# def assert_accept_mimetype(self, mimetype, expect=None):
+# """Assert that a request with given mimetype in the accept header,
+# gives a response with the appropriate content-type."""
+# if expect is None:
+# expect = mimetype
+#
+# resp = self.client.get(reverse(views.RootResource), HTTP_ACCEPT=mimetype)
+#
+# self.assertEquals(resp['content-type'], expect)
+#
+#
+# def dont_test_accept_json(self):
+# """Ensure server responds with Content-Type of JSON when requested."""
+# self.assert_accept_mimetype('application/json')
+#
+# def dont_test_accept_xml(self):
+# """Ensure server responds with Content-Type of XML when requested."""
+# self.assert_accept_mimetype('application/xml')
+#
+# def dont_test_accept_json_when_prefered_to_xml(self):
+# """Ensure server responds with Content-Type of JSON when it is the client's prefered choice."""
+# self.assert_accept_mimetype('application/json;q=0.9, application/xml;q=0.1', expect='application/json')
+#
+# def dont_test_accept_xml_when_prefered_to_json(self):
+# """Ensure server responds with Content-Type of XML when it is the client's prefered choice."""
+# self.assert_accept_mimetype('application/json;q=0.1, application/xml;q=0.9', expect='application/xml')
+#
+# def dont_test_default_json_prefered(self):
+# """Ensure server responds with JSON in preference to XML."""
+# self.assert_accept_mimetype('application/json,application/xml', expect='application/json')
+#
+# def dont_test_accept_generic_subtype_format(self):
+# """Ensure server responds with an appropriate type, when the subtype is left generic."""
+# self.assert_accept_mimetype('text/*', expect='text/html')
+#
+# def dont_test_accept_generic_type_format(self):
+# """Ensure server responds with an appropriate type, when the type and subtype are left generic."""
+# self.assert_accept_mimetype('*/*', expect='application/json')
+#
+# def dont_test_invalid_accept_header_returns_406(self):
+# """Ensure server returns a 406 (not acceptable) response if we set the Accept header to junk."""
+# resp = self.client.get(reverse(views.RootResource), HTTP_ACCEPT='invalid/invalid')
+# self.assertNotEquals(resp['content-type'], 'invalid/invalid')
+# self.assertEquals(resp.status_code, 406)
+#
+# def dont_test_prefer_specific_over_generic(self): # This test is broken right now
+# """More specific accept types have precedence over less specific types."""
+# self.assert_accept_mimetype('application/xml, */*', expect='application/xml')
+# self.assert_accept_mimetype('*/*, application/xml', expect='application/xml')
+#
+#
+# class AllowedMethodsTests(TestCase):
+# """Basic tests to check that only allowed operations may be performed on a Resource"""
+#
+# def dont_test_reading_a_read_only_resource_is_allowed(self):
+# """GET requests on a read only resource should default to a 200 (OK) response"""
+# resp = self.client.get(reverse(views.RootResource))
+# self.assertEquals(resp.status_code, 200)
+#
+# def dont_test_writing_to_read_only_resource_is_not_allowed(self):
+# """PUT requests on a read only resource should default to a 405 (method not allowed) response"""
+# resp = self.client.put(reverse(views.RootResource), {})
+# self.assertEquals(resp.status_code, 405)
#
# def test_reading_write_only_not_allowed(self):
# resp = self.client.get(reverse(views.WriteOnlyResource))
@@ -178,32 +179,33 @@ class TestRotation(TestCase):
models.BlogPost.objects.all().delete()
def test_get_to_root(self):
- '''Simple test to demonstrate how the requestfactory needs to be used'''
+ '''Simple get to the *root* url of blogposts'''
request = self.factory.get('/blog-post')
- view = views.BlogPosts.as_view()
+ view = ListOrCreateModelView.as_view(resource=urls.BlogPostResource)
response = view(request)
self.assertEqual(response.status_code, 200)
def test_blogposts_not_exceed_MAX_POSTS(self):
'''Posting blog-posts should not result in more than MAX_POSTS items stored.'''
- for post in range(views.MAX_POSTS + 5):
+ for post in range(models.MAX_POSTS + 5):
form_data = {'title': 'This is post #%s' % post, 'content': 'This is the content of post #%s' % post}
request = self.factory.post('/blog-post', data=form_data)
- view = views.BlogPosts.as_view()
+ view = ListOrCreateModelView.as_view(resource=urls.BlogPostResource)
view(request)
- self.assertEquals(len(models.BlogPost.objects.all()),views.MAX_POSTS)
+ self.assertEquals(len(models.BlogPost.objects.all()),models.MAX_POSTS)
def test_fifo_behaviour(self):
'''It's fine that the Blogposts are capped off at MAX_POSTS. But we want to make sure we see FIFO behaviour.'''
for post in range(15):
form_data = {'title': '%s' % post, 'content': 'This is the content of post #%s' % post}
request = self.factory.post('/blog-post', data=form_data)
- view = views.BlogPosts.as_view()
+ view = ListOrCreateModelView.as_view(resource=urls.BlogPostResource)
view(request)
request = self.factory.get('/blog-post')
- view = views.BlogPosts.as_view()
+ view = ListOrCreateModelView.as_view(resource=urls.BlogPostResource)
response = view(request)
response_posts = json.loads(response.content)
response_titles = [d['title'] for d in response_posts]
- self.assertEquals(response_titles, ['%s' % i for i in range(views.MAX_POSTS - 5, views.MAX_POSTS + 5)])
+ response_titles.reverse()
+ self.assertEquals(response_titles, ['%s' % i for i in range(models.MAX_POSTS - 5, models.MAX_POSTS + 5)])
\ No newline at end of file
diff --git a/examples/blogpost/urls.py b/examples/blogpost/urls.py
index c677b8fa..e9bd2754 100644
--- a/examples/blogpost/urls.py
+++ b/examples/blogpost/urls.py
@@ -1,36 +1,11 @@
from django.conf.urls.defaults import patterns, url
-from django.core.urlresolvers import reverse
-
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
-from djangorestframework.resources import ModelResource
-
-from blogpost.models import BlogPost, Comment
-
-
-class BlogPostResource(ModelResource):
- """
- A Blog Post has a *title* and *content*, and can be associated with zero or more comments.
- """
- model = BlogPost
- fields = ('created', 'title', 'slug', 'content', 'url', 'comments')
- ordering = ('-created',)
-
- def comments(self, instance):
- return reverse('comments', kwargs={'blogpost': instance.key})
-
-
-class CommentResource(ModelResource):
- """
- A Comment is associated with a given Blog Post and has a *username* and *comment*, and optionally a *rating*.
- """
- model = Comment
- fields = ('username', 'comment', 'created', 'rating', 'url', 'blogpost')
- ordering = ('-created',)
+from blogpost.resources import BlogPostResource, CommentResource
urlpatterns = patterns('',
url(r'^$', ListOrCreateModelView.as_view(resource=BlogPostResource), name='blog-posts-root'),
- url(r'^(?P<key>[^/]+)/$', InstanceModelView.as_view(resource=BlogPostResource)),
+ url(r'^(?P<key>[^/]+)/$', InstanceModelView.as_view(resource=BlogPostResource), name='blog-post'),
url(r'^(?P<blogpost>[^/]+)/comments/$', ListOrCreateModelView.as_view(resource=CommentResource), name='comments'),
url(r'^(?P<blogpost>[^/]+)/comments/(?P<id>[^/]+)/$', InstanceModelView.as_view(resource=CommentResource)),
)
diff --git a/examples/modelresourceexample/resources.py b/examples/modelresourceexample/resources.py
new file mode 100644
index 00000000..634ea6b3
--- /dev/null
+++ b/examples/modelresourceexample/resources.py
@@ -0,0 +1,7 @@
+from djangorestframework.resources import ModelResource
+from modelresourceexample.models import MyModel
+
+class MyModelResource(ModelResource):
+ model = MyModel
+ fields = ('foo', 'bar', 'baz', 'url')
+ ordering = ('created',)
diff --git a/examples/modelresourceexample/urls.py b/examples/modelresourceexample/urls.py
index bb71ddd3..b6a16542 100644
--- a/examples/modelresourceexample/urls.py
+++ b/examples/modelresourceexample/urls.py
@@ -1,14 +1,8 @@
from django.conf.urls.defaults import patterns, url
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
-from djangorestframework.resources import ModelResource
-from modelresourceexample.models import MyModel
-
-class MyModelResource(ModelResource):
- model = MyModel
- fields = ('foo', 'bar', 'baz', 'url')
- ordering = ('created',)
+from modelresourceexample.resources import MyModelResource
urlpatterns = patterns('',
url(r'^$', ListOrCreateModelView.as_view(resource=MyModelResource), name='model-resource-root'),
- url(r'^([0-9]+)/$', InstanceModelView.as_view(resource=MyModelResource)),
+ url(r'^(?P<pk>[0-9]+)/$', InstanceModelView.as_view(resource=MyModelResource)),
)
diff --git a/examples/modelresourceexample/views.py b/examples/permissionsexample/__init__.py
index e69de29b..e69de29b 100644
--- a/examples/modelresourceexample/views.py
+++ b/examples/permissionsexample/__init__.py
diff --git a/examples/permissionsexample/urls.py b/examples/permissionsexample/urls.py
new file mode 100644
index 00000000..d17f5159
--- /dev/null
+++ b/examples/permissionsexample/urls.py
@@ -0,0 +1,6 @@
+from django.conf.urls.defaults import patterns, url
+from permissionsexample.views import ThrottlingExampleView
+
+urlpatterns = patterns('',
+ url(r'^$', ThrottlingExampleView.as_view(), name='throttled-resource'),
+)
diff --git a/examples/permissionsexample/views.py b/examples/permissionsexample/views.py
new file mode 100644
index 00000000..20e7cba7
--- /dev/null
+++ b/examples/permissionsexample/views.py
@@ -0,0 +1,20 @@
+from djangorestframework.views import View
+from djangorestframework.permissions import PerUserThrottling
+
+
+class ThrottlingExampleView(View):
+ """
+ A basic read-only View that has a **per-user throttle** of 10 requests per minute.
+
+ If a user exceeds the 10 requests limit within a period of one minute, the
+ throttle will be applied until 60 seconds have passed since the first request.
+ """
+
+ permissions = ( PerUserThrottling, )
+ throttle = '10/min'
+
+ def get(self, request):
+ """
+ Handle GET requests.
+ """
+ return "Successful response to GET request because throttle is not yet active." \ No newline at end of file
diff --git a/examples/pygments_api/views.py b/examples/pygments_api/views.py
index 76647107..e50029f6 100644
--- a/examples/pygments_api/views.py
+++ b/examples/pygments_api/views.py
@@ -46,19 +46,12 @@ class HTMLRenderer(BaseRenderer):
media_type = 'text/html'
-
-class PygmentsFormResource(FormResource):
- """
- """
- form = PygmentsForm
-
-
class PygmentsRoot(View):
"""
- This example demonstrates a simple RESTful Web API aound the awesome pygments library.
+ This example demonstrates a simple RESTful Web API around the awesome pygments library.
This top level resource is used to create highlighted code snippets, and to list all the existing code snippets.
"""
- resource = PygmentsFormResource
+ form = PygmentsForm
def get(self, request):
"""
diff --git a/examples/resourceexample/urls.py b/examples/resourceexample/urls.py
index cb6435bb..6e141f3c 100644
--- a/examples/resourceexample/urls.py
+++ b/examples/resourceexample/urls.py
@@ -1,7 +1,7 @@
from django.conf.urls.defaults import patterns, url
-from resourceexample.views import ExampleResource, AnotherExampleResource
+from resourceexample.views import ExampleView, AnotherExampleView
urlpatterns = patterns('',
- url(r'^$', ExampleResource.as_view(), name='example-resource'),
- url(r'^(?P<num>[0-9]+)/$', AnotherExampleResource.as_view(), name='another-example-resource'),
+ url(r'^$', ExampleView.as_view(), name='example-resource'),
+ url(r'^(?P<num>[0-9]+)/$', AnotherExampleView.as_view(), name='another-example'),
)
diff --git a/examples/resourceexample/views.py b/examples/resourceexample/views.py
index 29651fbf..990c7834 100644
--- a/examples/resourceexample/views.py
+++ b/examples/resourceexample/views.py
@@ -1,42 +1,45 @@
from django.core.urlresolvers import reverse
from djangorestframework.views import View
-from djangorestframework.resources import FormResource
from djangorestframework.response import Response
from djangorestframework import status
from resourceexample.forms import MyForm
-class MyFormValidation(FormResource):
- """
- A resource which applies form validation on the input.
- """
- form = MyForm
-
-class ExampleResource(View):
+class ExampleView(View):
"""
- A basic read-only resource that points to 3 other resources.
+ A basic read-only view that points to 3 other views.
"""
def get(self, request):
- return {"Some other resources": [reverse('another-example-resource', kwargs={'num':num}) for num in range(3)]}
+ """
+ Handle GET requests, returning a list of URLs pointing to 3 other views.
+ """
+ return {"Some other resources": [reverse('another-example', kwargs={'num':num}) for num in range(3)]}
-class AnotherExampleResource(View):
+class AnotherExampleView(View):
"""
- A basic GET-able/POST-able resource.
+ A basic view, that can be handle GET and POST requests.
+ Applies some simple form validation on POST requests.
"""
- resource = MyFormValidation
+ form = MyForm
def get(self, request, num):
- """Handle GET requests"""
+ """
+ Handle GET requests.
+ Returns a simple string indicating which view the GET request was for.
+ """
if int(num) > 2:
return Response(status.HTTP_404_NOT_FOUND)
return "GET request to AnotherExampleResource %s" % num
def post(self, request, num):
- """Handle POST requests"""
+ """
+ Handle POST requests, with form validation.
+ Returns a simple string indicating what content was supplied.
+ """
if int(num) > 2:
return Response(status.HTTP_404_NOT_FOUND)
return "POST request to AnotherExampleResource %s, with content: %s" % (num, repr(self.CONTENT))
diff --git a/examples/sandbox/views.py b/examples/sandbox/views.py
index 1c55c28f..1e326f43 100644
--- a/examples/sandbox/views.py
+++ b/examples/sandbox/views.py
@@ -31,4 +31,6 @@ class Sandbox(View):
{'name': 'Simple Mixin-only example', 'url': reverse('mixin-view')},
{'name': 'Object store API', 'url': reverse('object-store-root')},
{'name': 'Code highlighting API', 'url': reverse('pygments-root')},
- {'name': 'Blog posts API', 'url': reverse('blog-posts-root')}]
+ {'name': 'Blog posts API', 'url': reverse('blog-posts-root')},
+ {'name': 'Permissions example', 'url': reverse('throttled-resource')}
+ ]
diff --git a/examples/urls.py b/examples/urls.py
index cf4d4042..08d97a14 100644
--- a/examples/urls.py
+++ b/examples/urls.py
@@ -10,6 +10,7 @@ urlpatterns = patterns('',
(r'^object-store/', include('objectstore.urls')),
(r'^pygments/', include('pygments_api.urls')),
(r'^blog-post/', include('blogpost.urls')),
+ (r'^permissions-example/', include('permissionsexample.urls')),
(r'^', include('djangorestframework.urls')),
)