diff options
| -rw-r--r-- | README.txt | 20 | ||||
| -rw-r--r-- | djangorestframework/__init__.py (renamed from flywheel/__init__.py) | 0 | ||||
| -rw-r--r-- | djangorestframework/authenticators.py (renamed from flywheel/authenticators.py) | 0 | ||||
| -rw-r--r-- | djangorestframework/emitters.py (renamed from flywheel/emitters.py) | 8 | ||||
| -rw-r--r-- | djangorestframework/modelresource.py (renamed from flywheel/modelresource.py) | 42 | ||||
| -rw-r--r-- | djangorestframework/parsers.py (renamed from flywheel/parsers.py) | 2 | ||||
| -rw-r--r-- | djangorestframework/resource.py (renamed from flywheel/resource.py) | 4 | ||||
| -rw-r--r-- | djangorestframework/response.py (renamed from flywheel/response.py) | 0 | ||||
| -rw-r--r-- | djangorestframework/templates/emitter.html (renamed from flywheel/templates/emitter.html) | 0 | ||||
| -rw-r--r-- | djangorestframework/templates/emitter.txt (renamed from flywheel/templates/emitter.txt) | 0 | ||||
| -rw-r--r-- | djangorestframework/templatetags/__init__.py (renamed from flywheel/templatetags/__init__.py) | 0 | ||||
| -rw-r--r-- | djangorestframework/templatetags/add_query_param.py (renamed from flywheel/templatetags/add_query_param.py) | 0 | ||||
| -rw-r--r-- | djangorestframework/templatetags/urlize_quoted_links.py (renamed from flywheel/templatetags/urlize_quoted_links.py) | 2 | ||||
| -rw-r--r-- | djangorestframework/utils.py (renamed from flywheel/utils.py) | 0 | ||||
| -rw-r--r-- | docs/conf.py | 2 | ||||
| -rw-r--r-- | docs/index.rst | 28 | ||||
| -rw-r--r-- | docs/requirements.txt | 8 | ||||
| -rw-r--r-- | examples/blogpost/views.py | 6 | ||||
| -rw-r--r-- | examples/objectstore/views.py | 4 | ||||
| -rw-r--r-- | examples/pygments_api/views.py | 6 | ||||
| -rw-r--r-- | examples/requirements.txt | 6 | ||||
| -rw-r--r-- | examples/settings.py | 9 | ||||
| -rw-r--r-- | examples/simpleexample/__init__.py | 0 | ||||
| -rw-r--r-- | examples/simpleexample/models.py | 23 | ||||
| -rw-r--r-- | examples/simpleexample/urls.py | 6 | ||||
| -rw-r--r-- | examples/simpleexample/views.py | 18 | ||||
| -rw-r--r-- | examples/urls.py | 27 | ||||
| -rw-r--r-- | requirements.txt | 2 | 
28 files changed, 155 insertions, 68 deletions
| @@ -1,17 +1,21 @@ -# To install django-rest-framework... -# -# Requirements: -#   python2.6 -#   virtualenv +# To install django-rest-framework in a virtualenv environment...  hg clone https://tomchristie@bitbucket.org/tomchristie/django-rest-framework  cd django-rest-framework/  virtualenv --no-site-packages --distribute --python=python2.6 env  source ./env/bin/activate -pip install -r ./requirements.txt -python ./src/manage.py test +pip install -r requirements.txt  # To build the documentation... -sphinx-build -c docs -b html -d cache docs html +pip install -r docs/requirements.txt +sphinx-build -c docs -b html -d docs-build docs html + +# To run the examples... + +pip install -r examples/requirements.txt +cd examples +export PYTHONPATH=.. +python manage.py syncdb +python manage.py runserver diff --git a/flywheel/__init__.py b/djangorestframework/__init__.py index e69de29b..e69de29b 100644 --- a/flywheel/__init__.py +++ b/djangorestframework/__init__.py diff --git a/flywheel/authenticators.py b/djangorestframework/authenticators.py index 8de182de..8de182de 100644 --- a/flywheel/authenticators.py +++ b/djangorestframework/authenticators.py diff --git a/flywheel/emitters.py b/djangorestframework/emitters.py index f548e1d9..a69407f1 100644 --- a/flywheel/emitters.py +++ b/djangorestframework/emitters.py @@ -1,5 +1,5 @@  """Emitters are used to serialize a Resource's output into specific media types. -FlyWheel also provides HTML and PlainText emitters that help self-document the API, +django-rest-framework also provides HTML and PlainText emitters that help self-document the API,  by serializing the output along with documentation regarding the Resource, output status and headers,  and providing forms and links depending on the allowed methods, emitters and parsers on the Resource.   """ @@ -7,8 +7,8 @@ from django.conf import settings  from django.template import RequestContext, loader  from django import forms -from flywheel.response import NoContent -from flywheel.utils import dict2xml, url_resolves +from djangorestframework.response import NoContent +from djangorestframework.utils import dict2xml, url_resolves  from urllib import quote_plus  import string @@ -193,7 +193,7 @@ class XMLEmitter(BaseEmitter):  class DocumentingHTMLEmitter(DocumentingTemplateEmitter):      """Emitter which provides a browsable HTML interface for an API. -    See the examples listed in the FlyWheel documentation to see this in actions.""" +    See the examples listed in the django-rest-framework documentation to see this in actions."""      media_type = 'text/html'      template = 'emitter.html' diff --git a/flywheel/modelresource.py b/djangorestframework/modelresource.py index d68ec79e..a9605d4a 100644 --- a/flywheel/modelresource.py +++ b/djangorestframework/modelresource.py @@ -2,8 +2,8 @@ from django.forms import ModelForm  from django.db.models.query import QuerySet  from django.db.models import Model -from flywheel.response import status, Response, ResponseException -from flywheel.resource import Resource +from djangorestframework.response import status, Response, ResponseException +from djangorestframework.resource import Resource  import decimal  import inspect @@ -336,28 +336,41 @@ class ModelResource(Resource):          return _any(data, self.fields) -    def post(self, request, content, *args, **kwargs): +    def post(self, request, auth, content, *args, **kwargs):          # TODO: test creation on a non-existing resource url          all_kw_args = dict(content.items() + kwargs.items()) -        instance = self.model(**all_kw_args) +        if args: +            instance = self.model(pk=args[-1], **all_kw_args) +        else: +            instance = self.model(**all_kw_args)          instance.save()          headers = {}          if hasattr(instance, 'get_absolute_url'):              headers['Location'] = self.add_domain(instance.get_absolute_url())          return Response(status.HTTP_201_CREATED, instance, headers) -    def get(self, request, *args, **kwargs): +    def get(self, request, auth, *args, **kwargs):          try: -            instance = self.model.objects.get(**kwargs) +            if args: +                # If we have any none kwargs then assume the last represents the primrary key +                instance = self.model.objects.get(pk=args[-1], **kwargs) +            else: +                # Otherwise assume the kwargs uniquely identify the model +                instance = self.model.objects.get(**kwargs)          except self.model.DoesNotExist:              raise ResponseException(status.HTTP_404_NOT_FOUND)          return instance -    def put(self, request, content, *args, **kwargs): +    def put(self, request, auth, content, *args, **kwargs):          # TODO: update on the url of a non-existing resource url doesn't work correctly at the moment - will end up with a new url           try: -            instance = self.model.objects.get(**kwargs)     +            if args: +                # If we have any none kwargs then assume the last represents the primrary key +                instance = self.model.objects.get(pk=args[-1], **kwargs) +            else: +                # Otherwise assume the kwargs uniquely identify the model +                instance = self.model.objects.get(**kwargs)              for (key, val) in content.items():                  setattr(instance, key, val)          except self.model.DoesNotExist: @@ -367,9 +380,14 @@ class ModelResource(Resource):          instance.save()          return instance -    def delete(self, request, *args, **kwargs): +    def delete(self, request, auth, *args, **kwargs):          try: -            instance = self.model.objects.get(**kwargs) +            if args: +                # If we have any none kwargs then assume the last represents the primrary key +                instance = self.model.objects.get(pk=args[-1], **kwargs) +            else: +                # Otherwise assume the kwargs uniquely identify the model +                instance = self.model.objects.get(**kwargs)          except self.model.DoesNotExist:              raise ResponseException(status.HTTP_404_NOT_FOUND, None, {}) @@ -382,7 +400,7 @@ class RootModelResource(ModelResource):      allowed_methods = ('GET', 'POST')      queryset = None -    def get(self, request, *args, **kwargs): +    def get(self, request, auth, *args, **kwargs):          queryset = self.queryset if self.queryset else self.model.objects.all()          return queryset @@ -396,7 +414,7 @@ class QueryModelResource(ModelResource):      def get_form(self, data=None):          return None -    def get(self, request, *args, **kwargs): +    def get(self, request, auth, *args, **kwargs):          queryset = self.queryset if self.queryset else self.model.objects.all()          return queryset diff --git a/flywheel/parsers.py b/djangorestframework/parsers.py index 98232a96..a656e2eb 100644 --- a/flywheel/parsers.py +++ b/djangorestframework/parsers.py @@ -1,4 +1,4 @@ -from flywheel.response import status, ResponseException +from djangorestframework.response import status, ResponseException  try:      import json diff --git a/flywheel/resource.py b/djangorestframework/resource.py index 2a8554f3..d06d51b0 100644 --- a/flywheel/resource.py +++ b/djangorestframework/resource.py @@ -2,8 +2,8 @@ from django.contrib.sites.models import Site  from django.core.urlresolvers import reverse  from django.http import HttpResponse -from flywheel import emitters, parsers, authenticators -from flywheel.response import status, Response, ResponseException +from djangorestframework import emitters, parsers, authenticators +from djangorestframework.response import status, Response, ResponseException  from decimal import Decimal  import re diff --git a/flywheel/response.py b/djangorestframework/response.py index 4f23bb0a..4f23bb0a 100644 --- a/flywheel/response.py +++ b/djangorestframework/response.py diff --git a/flywheel/templates/emitter.html b/djangorestframework/templates/emitter.html index d21350cd..d21350cd 100644 --- a/flywheel/templates/emitter.html +++ b/djangorestframework/templates/emitter.html diff --git a/flywheel/templates/emitter.txt b/djangorestframework/templates/emitter.txt index 1cc7d1d7..1cc7d1d7 100644 --- a/flywheel/templates/emitter.txt +++ b/djangorestframework/templates/emitter.txt diff --git a/flywheel/templatetags/__init__.py b/djangorestframework/templatetags/__init__.py index e69de29b..e69de29b 100644 --- a/flywheel/templatetags/__init__.py +++ b/djangorestframework/templatetags/__init__.py diff --git a/flywheel/templatetags/add_query_param.py b/djangorestframework/templatetags/add_query_param.py index 91c1a312..91c1a312 100644 --- a/flywheel/templatetags/add_query_param.py +++ b/djangorestframework/templatetags/add_query_param.py diff --git a/flywheel/templatetags/urlize_quoted_links.py b/djangorestframework/templatetags/urlize_quoted_links.py index 60088cf6..eea424a4 100644 --- a/flywheel/templatetags/urlize_quoted_links.py +++ b/djangorestframework/templatetags/urlize_quoted_links.py @@ -97,4 +97,4 @@ urlize_quoted_links.is_safe = True  # Register urlize_quoted_links as a custom filter  # http://docs.djangoproject.com/en/dev/howto/custom-template-tags/  register = template.Library() -register.filter(urlize_quoted_links)
\ No newline at end of file +register.filter(urlize_quoted_links) diff --git a/flywheel/utils.py b/djangorestframework/utils.py index f9bbc0fe..f9bbc0fe 100644 --- a/flywheel/utils.py +++ b/djangorestframework/utils.py diff --git a/docs/conf.py b/docs/conf.py index 71cacb3d..3689a636 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,7 @@  import sys, os  sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) -sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'flywheel')) +sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'djangorestframework'))  sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'examples'))  import settings  from django.core.management import setup_environ diff --git a/docs/index.rst b/docs/index.rst index 7a871a5c..7da3f017 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,10 +26,10 @@ Requirements  Installation & Setup  -------------------- -The django-rest-framework project is hosted as a `mercurial repository on bitbucket <https://bitbucket.org/tomchristie/flywheel>`_. +The django-rest-framework project is hosted as a `mercurial repository on bitbucket <https://bitbucket.org/tomchristie/django-rest-framework>`_.  To get a local copy of the repository use mercurial:: -    hg clone https://tomchristie@bitbucket.org/tomchristie/flywheel +    hg clone https://tomchristie@bitbucket.org/tomchristie/django-rest-framework  To add django-rest-framework to a django project: @@ -43,27 +43,15 @@ Getting Started  Often you'll want parts of your API to directly map to existing Models.  At it's simplest this looks something like this... -``views.py``:: +``urls.py`` -    from djangorestframework.modelresource import ModelResource, ModelRootResource -    from models import MyModel +.. include:: ../examples/simpleexample/urls.py +    :literal: -    class MyModelRootResource(ModelRootResource): -	"""A create/list resource for MyModel.""" -        allowed_methods = ('GET', 'POST') -        model = MyModel +``views.py`` -    class MyModelResource(ModelResource): -	"""A read/update/delete resource for MyModel.""" -        allowed_methods = ('GET', 'PUT', 'DELETE') -        model = MyModel - -``urls.py``:: - -    urlpatterns += patterns('myapp.views', -        url(r'^mymodel/$',         'MyModelRootResource'),  -        url(r'^mymodel/([^/]+)/$', 'MyModelResource'),  -    ) +.. include:: ../examples/simpleexample/views.py +    :literal:  Examples diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..77cdf485 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,8 @@ +# Documentation requires Django & Sphinx, and their dependencies... + +Django==1.2.4 +Jinja2==2.5.5 +Pygments==1.4 +Sphinx==1.0.7 +docutils==0.7 +wsgiref==0.1.2 diff --git a/examples/blogpost/views.py b/examples/blogpost/views.py index c5be2544..bfb53b5d 100644 --- a/examples/blogpost/views.py +++ b/examples/blogpost/views.py @@ -1,6 +1,6 @@ -from flywheel.response import Response, status -from flywheel.resource import Resource -from flywheel.modelresource import ModelResource, RootModelResource +from djangorestframework.response import Response, status +from djangorestframework.resource import Resource +from djangorestframework.modelresource import ModelResource, RootModelResource  from blogpost.models import BlogPost, Comment  BLOG_POST_FIELDS = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url') diff --git a/examples/objectstore/views.py b/examples/objectstore/views.py index 4681fe70..90bdb9e3 100644 --- a/examples/objectstore/views.py +++ b/examples/objectstore/views.py @@ -1,7 +1,7 @@  from django.conf import settings -from flywheel.resource import Resource -from flywheel.response import Response, status +from djangorestframework.resource import Resource +from djangorestframework.response import Response, status  import pickle  import os diff --git a/examples/pygments_api/views.py b/examples/pygments_api/views.py index d9082ada..e22705d9 100644 --- a/examples/pygments_api/views.py +++ b/examples/pygments_api/views.py @@ -1,8 +1,8 @@  from django.conf import settings -from flywheel.resource import Resource -from flywheel.response import Response, status -from flywheel.emitters import BaseEmitter +from djangorestframework.resource import Resource +from djangorestframework.response import Response, status +from djangorestframework.emitters import BaseEmitter  from pygments.formatters import HtmlFormatter  from pygments.lexers import get_lexer_by_name diff --git a/examples/requirements.txt b/examples/requirements.txt new file mode 100644 index 00000000..4ae9e3c7 --- /dev/null +++ b/examples/requirements.txt @@ -0,0 +1,6 @@ +# For the examples we need Django, pygments and httplib2... + +Django==1.2.4 +wsgiref==0.1.2 +Pygments==1.4 +httplib2==0.6.0 diff --git a/examples/settings.py b/examples/settings.py index 0ae3bf56..4aa5dd00 100644 --- a/examples/settings.py +++ b/examples/settings.py @@ -93,9 +93,10 @@ INSTALLED_APPS = (      'django.contrib.sessions',      'django.contrib.sites',      'django.contrib.messages', -    'django.contrib.admin', -    'flywheel', -    'blogpost', +    #'django.contrib.admin', +    'djangorestframework', +    'simpleexample',      'objectstore', -    'pygments_api' +    'pygments_api', +    'blogpost',  ) diff --git a/examples/simpleexample/__init__.py b/examples/simpleexample/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/examples/simpleexample/__init__.py diff --git a/examples/simpleexample/models.py b/examples/simpleexample/models.py new file mode 100644 index 00000000..13867f61 --- /dev/null +++ b/examples/simpleexample/models.py @@ -0,0 +1,23 @@ +from django.db import models + +MAX_INSTANCES = 20 + +class MyModel(models.Model): +    foo = models.BooleanField() +    bar = models.IntegerField(help_text='Must be an integer.') +    baz = models.CharField(max_length=32, help_text='Free text.  Max length 32 chars.') +    created = models.DateTimeField(auto_now_add=True) +     +    class Meta: +        ordering = ('created',) + +    def save(self, *args, **kwargs): +        """For the purposes of the sandbox, limit the maximum number of stored models.""" +        while MyModel.objects.all().count() > MAX_INSTANCES: +            MyModel.objects.all()[0].delete() +        super(MyModel, self).save(*args, **kwargs) +     +    @models.permalink +    def get_absolute_url(self): +        return ('simpleexample.views.MyModelResource', (self.pk,)) + diff --git a/examples/simpleexample/urls.py b/examples/simpleexample/urls.py new file mode 100644 index 00000000..d853ba5a --- /dev/null +++ b/examples/simpleexample/urls.py @@ -0,0 +1,6 @@ +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns('simpleexample.views', +    url(r'^$',         'MyModelRootResource'), +    url(r'^([0-9]+)/$', 'MyModelResource'), +) diff --git a/examples/simpleexample/views.py b/examples/simpleexample/views.py new file mode 100644 index 00000000..1f113ac2 --- /dev/null +++ b/examples/simpleexample/views.py @@ -0,0 +1,18 @@ +from djangorestframework.modelresource import ModelResource, RootModelResource +from simpleexample.models import MyModel + +FIELDS = ('foo', 'bar', 'baz', 'absolute_url') + +class MyModelRootResource(RootModelResource): +    """A create/list resource for MyModel. +    Available for both authenticated and anonymous access for the purposes of the sandbox.""" +    model = MyModel +    allowed_methods = anon_allowed_methods = ('GET', 'POST') +    fields = FIELDS + +class MyModelResource(ModelResource): +    """A read/update/delete resource for MyModel. +    Available for both authenticated and anonymous access for the purposes of the sandbox.""" +    model = MyModel +    allowed_methods = anon_allowed_methods = ('GET', 'PUT', 'DELETE') +    fields = FIELDS diff --git a/examples/urls.py b/examples/urls.py index b1dec13d..2b8e6fcd 100644 --- a/examples/urls.py +++ b/examples/urls.py @@ -1,14 +1,27 @@  from django.conf.urls.defaults import patterns, include -from django.contrib import admin +#from django.contrib import admin +from djangorestframework.resource import Resource + +#admin.autodiscover() + +class RootResource(Resource): +    allowed_methods = anon_allowed_methods = ('GET',) + +    def get(self, request, auth): +        return {'simple example': self.reverse('simpleexample.views.MyModelRootResource'), +                'pygments example': self.reverse('pygments_api.views.PygmentsRoot'), +                'object store example': self.reverse('objectstore.views.ObjectStoreRoot'), +                'blog post example': self.reverse('blogpost.views.BlogPostRoot'),} -admin.autodiscover()  urlpatterns = patterns('', -    (r'^pygments-example/', include('pygments_api.urls')), -    (r'^blog-post-example/', include('blogpost.urls')), -    (r'^object-store-example/', include('objectstore.urls')), +    (r'^$', RootResource), +    (r'^simple-example/', include('simpleexample.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'^admin/doc/', include('django.contrib.admindocs.urls')), +    #(r'^admin/', include(admin.site.urls)),  ) diff --git a/requirements.txt b/requirements.txt index 8144d828..84f0c4eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ +# Django and pip are required if installing into a virtualenv environment... +  Django==1.2.4  distribute==0.6.14  wsgiref==0.1.2 | 
