diff options
| author | tom christie tom@tomchristie.com | 2011-02-19 10:26:27 +0000 | 
|---|---|---|
| committer | tom christie tom@tomchristie.com | 2011-02-19 10:26:27 +0000 | 
| commit | 805aa03ec1871f6a766d9052b348ddce9e9843c3 (patch) | |
| tree | 8ab5b6a7396236aa45bbc61e8404cc77fc75a9c5 /examples | |
| parent | b749b950a1b4bede76b7e3900a6385779904902d (diff) | |
| download | django-rest-framework-805aa03ec1871f6a766d9052b348ddce9e9843c3.tar.bz2 | |
Yowzers.  Final big bunch of refactoring for 0.1 release.  Now support Django 1.3's views, admin style api is all polished off, loads of tests, new test project for running the test.  All sorts of goodness.  Getting ready to push this out now.
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/blogpost/models.py | 8 | ||||
| -rw-r--r-- | examples/blogpost/urls.py | 13 | ||||
| -rw-r--r-- | examples/blogpost/views.py | 22 | ||||
| -rw-r--r-- | examples/mixin/__init__.py | 0 | ||||
| -rw-r--r-- | examples/mixin/urls.py | 23 | ||||
| -rw-r--r-- | examples/modelresourceexample/models.py | 2 | ||||
| -rw-r--r-- | examples/modelresourceexample/urls.py | 5 | ||||
| -rw-r--r-- | examples/objectstore/urls.py | 9 | ||||
| -rw-r--r-- | examples/objectstore/views.py | 9 | ||||
| -rw-r--r-- | examples/pygments_api/urls.py | 9 | ||||
| -rw-r--r-- | examples/pygments_api/views.py | 6 | ||||
| -rw-r--r-- | examples/requirements.txt | 2 | ||||
| -rw-r--r-- | examples/resourceexample/urls.py | 7 | ||||
| -rw-r--r-- | examples/resourceexample/views.py | 5 | ||||
| -rw-r--r-- | examples/sandbox/__init__.py | 0 | ||||
| -rw-r--r-- | examples/sandbox/views.py | 35 | ||||
| -rw-r--r-- | examples/settings.py | 17 | ||||
| -rw-r--r-- | examples/templates/base.html | 7 | ||||
| -rw-r--r-- | examples/templates/registration/login.html | 26 | ||||
| -rw-r--r-- | examples/urls.py | 40 | 
20 files changed, 133 insertions, 112 deletions
| diff --git a/examples/blogpost/models.py b/examples/blogpost/models.py index e1968415..c85ca788 100644 --- a/examples/blogpost/models.py +++ b/examples/blogpost/models.py @@ -24,13 +24,13 @@ class BlogPost(models.Model):      @models.permalink      def get_absolute_url(self): -        return ('blogpost.views.BlogPostInstance', (), {'key': self.key}) +        return ('blog-post', (), {'key': self.key})      @property      @models.permalink      def comments_url(self):          """Link to a resource which lists all comments for this blog post.""" -        return ('blogpost.views.CommentRoot', (), {'blogpost_id': self.key}) +        return ('comments', (), {'blogpost_id': self.key})      def __unicode__(self):          return self.title @@ -52,11 +52,11 @@ class Comment(models.Model):      @models.permalink      def get_absolute_url(self): -        return ('blogpost.views.CommentInstance', (), {'blogpost': self.blogpost.key, 'id': self.id}) +        return ('comment', (), {'blogpost': self.blogpost.key, 'id': self.id})      @property      @models.permalink      def blogpost_url(self):          """Link to the blog post resource which this comment corresponds to.""" -        return ('blogpost.views.BlogPostInstance', (), {'key': self.blogpost.key}) +        return ('blog-post', (), {'key': self.blogpost.key}) diff --git a/examples/blogpost/urls.py b/examples/blogpost/urls.py index ee209b3e..b2df96a1 100644 --- a/examples/blogpost/urls.py +++ b/examples/blogpost/urls.py @@ -1,8 +1,9 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls.defaults import patterns, url +from blogpost.views import BlogPosts, BlogPostInstance, Comments, CommentInstance -urlpatterns = patterns('blogpost.views', -    (r'^$', 'BlogPostRoot'), -    (r'^(?P<key>[^/]+)/$', 'BlogPostInstance'), -    (r'^(?P<blogpost_id>[^/]+)/comments/$', 'CommentRoot'), -    (r'^(?P<blogpost>[^/]+)/comments/(?P<id>[^/]+)/$', 'CommentInstance'), +urlpatterns = patterns('', +    url(r'^$', BlogPosts.as_view(), name='blog-posts'), +    url(r'^(?P<key>[^/]+)/$', BlogPostInstance.as_view(), name='blog-post'), +    url(r'^(?P<blogpost_id>[^/]+)/comments/$', Comments.as_view(), name='comments'), +    url(r'^(?P<blogpost>[^/]+)/comments/(?P<id>[^/]+)/$', CommentInstance.as_view(), name='comment'),  ) diff --git a/examples/blogpost/views.py b/examples/blogpost/views.py index bfb53b5d..0377b447 100644 --- a/examples/blogpost/views.py +++ b/examples/blogpost/views.py @@ -1,33 +1,33 @@  from djangorestframework.response import Response, status  from djangorestframework.resource import Resource  from djangorestframework.modelresource import ModelResource, RootModelResource -from blogpost.models import BlogPost, Comment +from blogpost import models  BLOG_POST_FIELDS = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url')  COMMENT_FIELDS = ('username', 'comment', 'created', 'rating', 'absolute_url', 'blogpost_url') -class BlogPostRoot(RootModelResource): +class BlogPosts(RootModelResource):      """A resource with which lists all existing blog posts and creates new blog posts.""" -    allowed_methods = ('GET', 'POST',) -    model = BlogPost +    anon_allowed_methods = allowed_methods = ('GET', 'POST',) +    model = models.BlogPost      fields = BLOG_POST_FIELDS  class BlogPostInstance(ModelResource):      """A resource which represents a single blog post.""" -    allowed_methods = ('GET', 'PUT', 'DELETE') -    model = BlogPost +    anon_allowed_methods = allowed_methods = ('GET', 'PUT', 'DELETE') +    model = models.BlogPost      fields = BLOG_POST_FIELDS -class CommentRoot(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.""" -    allowed_methods = ('GET', 'POST',) -    model = Comment +    anon_allowed_methods = allowed_methods = ('GET', 'POST',) +    model = models.Comment      fields = COMMENT_FIELDS  class CommentInstance(ModelResource):      """A resource which represents a single comment.""" -    allowed_methods = ('GET', 'PUT', 'DELETE') -    model = Comment +    anon_allowed_methods = allowed_methods = ('GET', 'PUT', 'DELETE') +    model = models.Comment      fields = COMMENT_FIELDS diff --git a/examples/mixin/__init__.py b/examples/mixin/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/examples/mixin/__init__.py diff --git a/examples/mixin/urls.py b/examples/mixin/urls.py new file mode 100644 index 00000000..05009284 --- /dev/null +++ b/examples/mixin/urls.py @@ -0,0 +1,23 @@ +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.response import Response + +from django.conf.urls.defaults import patterns, url +from django.core.urlresolvers import reverse + + +class ExampleView(EmitterMixin, View): +    """An example view using Django 1.3's class based views. +    Uses djangorestframework's EmitterMixin to provide support for multiple output formats.""" +    emitters = DEFAULT_EMITTERS + +    def get(self, request): +        response = Response(200, {'description': 'Some example content', +                                  'url': reverse('mixin-view')}) +        return self.emit(response) + + +urlpatterns = patterns('', +    url(r'^$', ExampleView.as_view(), name='mixin-view'), +) + diff --git a/examples/modelresourceexample/models.py b/examples/modelresourceexample/models.py index 036501d0..16047524 100644 --- a/examples/modelresourceexample/models.py +++ b/examples/modelresourceexample/models.py @@ -19,5 +19,5 @@ class MyModel(models.Model):      @models.permalink      def get_absolute_url(self): -        return ('modelresourceexample.views.MyModelResource', (self.pk,)) +        return ('my-model-resource', (self.pk,)) diff --git a/examples/modelresourceexample/urls.py b/examples/modelresourceexample/urls.py index c43cf56a..53d950cd 100644 --- a/examples/modelresourceexample/urls.py +++ b/examples/modelresourceexample/urls.py @@ -1,6 +1,7 @@  from django.conf.urls.defaults import patterns, url +from modelresourceexample.views import MyModelRootResource, MyModelResource  urlpatterns = patterns('modelresourceexample.views', -    url(r'^$',          'MyModelRootResource'), -    url(r'^([0-9]+)/$', 'MyModelResource'), +    url(r'^$',          MyModelRootResource.as_view(), name='my-model-root-resource'), +    url(r'^([0-9]+)/$', MyModelResource.as_view(), name='my-model-resource'),  ) diff --git a/examples/objectstore/urls.py b/examples/objectstore/urls.py index c04e731e..2c685f59 100644 --- a/examples/objectstore/urls.py +++ b/examples/objectstore/urls.py @@ -1,6 +1,7 @@ -from django.conf.urls.defaults import patterns - +from django.conf.urls.defaults import patterns, url +from objectstore.views import ObjectStoreRoot, StoredObject +   urlpatterns = patterns('objectstore.views', -    (r'^$', 'ObjectStoreRoot'),  -    (r'^(?P<key>[A-Za-z0-9_-]{1,64})/$', 'StoredObject'), +    url(r'^$', ObjectStoreRoot.as_view(), name='object-store-root'),  +    url(r'^(?P<key>[A-Za-z0-9_-]{1,64})/$', StoredObject.as_view(), name='stored-object'),  ) diff --git a/examples/objectstore/views.py b/examples/objectstore/views.py index e1b239dc..b3ed5533 100644 --- a/examples/objectstore/views.py +++ b/examples/objectstore/views.py @@ -1,4 +1,5 @@  from django.conf import settings +from django.core.urlresolvers import reverse  from djangorestframework.resource import Resource  from djangorestframework.response import Response, status @@ -29,7 +30,7 @@ class ObjectStoreRoot(Resource):      def get(self, request, auth):          """Return a list of all the stored object URLs."""          keys = sorted(os.listdir(OBJECT_STORE_DIR)) -        return [self.reverse(StoredObject, key=key) for key in keys] +        return [reverse('stored-object', kwargs={'key':key}) for key in keys]      def post(self, request, auth, content):          """Create a new stored object, with a unique key.""" @@ -37,9 +38,9 @@ class ObjectStoreRoot(Resource):          pathname = os.path.join(OBJECT_STORE_DIR, key)          pickle.dump(content, open(pathname, 'wb'))          remove_oldest_files(OBJECT_STORE_DIR, MAX_FILES) -        return Response(status.HTTP_201_CREATED, content, {'Location': self.reverse(StoredObject, key=key)}) -  -         +        return Response(status.HTTP_201_CREATED, content, {'Location': reverse('stored-object', kwargs={'key':key})}) + +  class StoredObject(Resource):      """Represents a stored object.      The object may be any picklable content.""" diff --git a/examples/pygments_api/urls.py b/examples/pygments_api/urls.py index f96f4518..905e31c5 100644 --- a/examples/pygments_api/urls.py +++ b/examples/pygments_api/urls.py @@ -1,6 +1,7 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls.defaults import patterns, url +from pygments_api.views import PygmentsRoot, PygmentsInstance -urlpatterns = patterns('pygments_api.views', -    (r'^$', 'PygmentsRoot'),  -    (r'^([a-zA-Z0-9-]+)/$', 'PygmentsInstance'), +urlpatterns = patterns('', +    url(r'^$', PygmentsRoot.as_view(), name='pygments-root'),  +    url(r'^([a-zA-Z0-9-]+)/$', PygmentsInstance.as_view(), name='pygments-instance'),  ) diff --git a/examples/pygments_api/views.py b/examples/pygments_api/views.py index e22705d9..84e5e703 100644 --- a/examples/pygments_api/views.py +++ b/examples/pygments_api/views.py @@ -1,4 +1,6 @@ +from __future__ import with_statement  # for python 2.5  from django.conf import settings +from django.core.urlresolvers import reverse  from djangorestframework.resource import Resource  from djangorestframework.response import Response, status @@ -41,7 +43,7 @@ class PygmentsRoot(Resource):      def get(self, request, auth):          """Return a list of all currently existing snippets."""          unique_ids = sorted(os.listdir(HIGHLIGHTED_CODE_DIR)) -        return [self.reverse(PygmentsInstance, 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):          """Create a new highlighed snippet and return it's location. @@ -59,7 +61,7 @@ class PygmentsRoot(Resource):          remove_oldest_files(HIGHLIGHTED_CODE_DIR, MAX_FILES) -        return Response(status.HTTP_201_CREATED, headers={'Location': self.reverse(PygmentsInstance, unique_id)}) +        return Response(status.HTTP_201_CREATED, headers={'Location': reverse('pygments-instance', args=[unique_id])})  class PygmentsInstance(Resource): diff --git a/examples/requirements.txt b/examples/requirements.txt index 4ae9e3c7..09cda945 100644 --- a/examples/requirements.txt +++ b/examples/requirements.txt @@ -4,3 +4,5 @@ Django==1.2.4  wsgiref==0.1.2  Pygments==1.4  httplib2==0.6.0 +Markdown==2.0.3 + diff --git a/examples/resourceexample/urls.py b/examples/resourceexample/urls.py index 828caef2..cb6435bb 100644 --- a/examples/resourceexample/urls.py +++ b/examples/resourceexample/urls.py @@ -1,6 +1,7 @@  from django.conf.urls.defaults import patterns, url +from resourceexample.views import ExampleResource, AnotherExampleResource -urlpatterns = patterns('resourceexample.views', -    url(r'^$',                 'ExampleResource'), -    url(r'^(?P<num>[0-9]+)/$', 'AnotherExampleResource'), +urlpatterns = patterns('', +    url(r'^$',                 ExampleResource.as_view(), name='example-resource'), +    url(r'^(?P<num>[0-9]+)/$', AnotherExampleResource.as_view(), name='another-example-resource'),  ) diff --git a/examples/resourceexample/views.py b/examples/resourceexample/views.py index e5bb5efa..c4462ee2 100644 --- a/examples/resourceexample/views.py +++ b/examples/resourceexample/views.py @@ -1,13 +1,14 @@ +from django.core.urlresolvers import reverse  from djangorestframework.resource import Resource  from djangorestframework.response import Response, status  from resourceexample.forms import MyForm  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): -        return {"Some other resources": [self.reverse(AnotherExampleResource, 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):      """A basic GET-able/POST-able resource.""" diff --git a/examples/sandbox/__init__.py b/examples/sandbox/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/examples/sandbox/__init__.py diff --git a/examples/sandbox/views.py b/examples/sandbox/views.py new file mode 100644 index 00000000..561bdb1d --- /dev/null +++ b/examples/sandbox/views.py @@ -0,0 +1,35 @@ +"""The root view for the examples provided with Django REST framework""" + +from django.core.urlresolvers import reverse +from djangorestframework.resource import Resource + + +class Sandbox(Resource): +    """This is the sandbox for the examples provided with [Django REST framework](http://django-rest-framework.org). + +    These examples are provided to help you get a better idea of the some of the features of RESTful APIs created using the framework. + +    All the example APIs allow anonymous access, and can be navigated either through the browser or from the command line... + +        bash: curl -X GET http://api.django-rest-framework.org/                           # (Use default emitter) +        bash: curl -X GET http://api.django-rest-framework.org/ -H 'Accept: text/plain'   # (Use plaintext documentation emitter) + +    The examples provided:  +    +    1. A basic example using the [Resource](http://django-rest-framework.org/library/resource.html) class. +    2. A basic example using the [ModelResource](http://django-rest-framework.org/library/modelresource.html) class. +    3. An basic example using Django 1.3's [class based views](http://docs.djangoproject.com/en/dev/topics/class-based-views/) and djangorestframework's [EmitterMixin](http://django-rest-framework.org/library/emitters.html). +    4. A generic object store API. +    5. A code highlighting API. +    6. A blog posts and comments API. + +    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): +        return [{'name': 'Simple Resource example', 'url': reverse('example-resource')}, +                {'name': 'Simple ModelResource example', 'url': reverse('my-model-root-resource')}, +                {'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')}] diff --git a/examples/settings.py b/examples/settings.py index 865dc394..c4cdd992 100644 --- a/examples/settings.py +++ b/examples/settings.py @@ -1,7 +1,4 @@ -# Django settings for src project. -import os - -BASE_DIR = os.path.dirname(__file__) +# Settings for djangorestframework examples project  DEBUG = True  TEMPLATE_DEBUG = DEBUG @@ -48,17 +45,23 @@ USE_L10N = True  # Absolute filesystem path to the directory that will hold user-uploaded files.  # Example: "/home/media/media.lawrence.com/" +# NOTE: Some of the djangorestframework examples use MEDIA_ROOT to store content.  MEDIA_ROOT = 'media/'  # URL that handles the media served from MEDIA_ROOT. Make sure to use a  # trailing slash if there is a path component (optional in other cases).  # Examples: "http://media.lawrence.com", "http://example.com/media/" +# NOTE: None of the djangorestframework examples serve media content via MEDIA_URL.   MEDIA_URL = ''  # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a  # trailing slash.  # Examples: "http://foo.com/media/", "/media/". -ADMIN_MEDIA_PREFIX = '/media/' +# NOTE: djangorestframework does not require the admin app to be installed, +# but it does require the admin media be served.  Django's test server will do +# this for you automatically, but in production you'll want to make sure you +# serve the admin media from somewhere. +ADMIN_MEDIA_PREFIX = '/admin-media/'  # Make this unique, and don't share it with anybody.  SECRET_KEY = 't&9mru2_k$t8e2-9uq-wu2a1)9v*us&j3i#lsqkt(lbx*vh1cu' @@ -84,16 +87,16 @@ TEMPLATE_DIRS = (      # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".      # Always use forward slashes, even on Windows.      # Don't forget to use absolute paths, not relative paths. -    os.path.join(BASE_DIR, 'templates')  ) +  INSTALLED_APPS = (      'django.contrib.auth',      'django.contrib.contenttypes',      'django.contrib.sessions',      'django.contrib.sites',      'django.contrib.messages', -    #'django.contrib.admin', +      'djangorestframework',      'resourceexample', diff --git a/examples/templates/base.html b/examples/templates/base.html deleted file mode 100644 index 1ff37dab..00000000 --- a/examples/templates/base.html +++ /dev/null @@ -1,7 +0,0 @@ -<html> -  <head> -  </head> -  <body> -{% block content %}{% endblock %} -  </body> -</html>
\ No newline at end of file diff --git a/examples/templates/registration/login.html b/examples/templates/registration/login.html deleted file mode 100644 index 9d0b481b..00000000 --- a/examples/templates/registration/login.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends "base.html" %} - -{% block content %} - -{% if form.errors %} -<p>Your username and password didn't match. Please try again.</p> -{% endif %} - -<form method="post" action="{% url django.contrib.auth.views.login %}"> -{% csrf_token %} -<table> -<tr> -    <td>{{ form.username.label_tag }}</td> -    <td>{{ form.username }}</td> -</tr> -<tr> -    <td>{{ form.password.label_tag }}</td> -    <td>{{ form.password }}</td> -</tr> -</table> - -<input type="submit" value="login" /> -<input type="hidden" name="next" value="{{ next }}" /> -</form> - -{% endblock %}
\ No newline at end of file diff --git a/examples/urls.py b/examples/urls.py index 41b80d58..03894e4e 100644 --- a/examples/urls.py +++ b/examples/urls.py @@ -1,37 +1,19 @@ -from django.conf.urls.defaults import patterns, include -#from django.contrib import admin -from djangorestframework.resource import Resource +from django.conf.urls.defaults import patterns, include, url +from sandbox.views import Sandbox -#admin.autodiscover() +urlpatterns = patterns('djangorestframework.views', +    (r'robots.txt', 'deny_robots'), +    (r'favicon.ico', 'favicon'), -class RootResource(Resource): -    """This is the sandbox for the examples provided with django-rest-framework. +    (r'^$', Sandbox.as_view()), -    These examples are here to help you get a better idea of the some of the -    features of django-rest-framework API, such as automatic form and model validation, -    support for multiple input and output media types, etc... - -    Please feel free to browse, create, edit and delete the resources here, either -    in the browser, from the command line, or programmatically.""" -    allowed_methods = anon_allowed_methods = ('GET',) - -    def get(self, request, auth): -        return {'Simple Resource example': self.reverse('resourceexample.views.ExampleResource'), -                'Simple ModelResource example': self.reverse('modelresourceexample.views.MyModelRootResource'), -                'Object store API (Resource)': self.reverse('objectstore.views.ObjectStoreRoot'), -                'A pygments pastebin API (Resource + forms)': self.reverse('pygments_api.views.PygmentsRoot'), -                'Blog posts API (ModelResource)': self.reverse('blogpost.views.BlogPostRoot'),} - - -urlpatterns = patterns('', -    (r'^$', RootResource), -    (r'^model-resource-example/', include('modelresourceexample.urls')),      (r'^resource-example/', include('resourceexample.urls')), +    (r'^model-resource-example/', include('modelresourceexample.urls')), +    (r'^mixin/', include('mixin.urls')),      (r'^object-store/', include('objectstore.urls')),      (r'^pygments/', include('pygments_api.urls')),      (r'^blog-post/', include('blogpost.urls')), -    (r'^accounts/login/$', 'django.contrib.auth.views.login'), -    (r'^accounts/logout/$', 'django.contrib.auth.views.logout'), -    #(r'^admin/doc/', include('django.contrib.admindocs.urls')), -    #(r'^admin/', include(admin.site.urls)), + +    (r'^accounts/login/$', 'api_login'), +    (r'^accounts/logout/$', 'api_logout'),  ) | 
