Rename to django-rest-framework, get simpleexample working

This commit is contained in:
tom christie tom@tomchristie.com 2011-01-30 18:30:39 +00:00
parent 8a470f031e
commit 42f2f9b40d
28 changed files with 155 additions and 68 deletions

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -1,4 +1,4 @@
from flywheel.response import status, ResponseException
from djangorestframework.response import status, ResponseException
try:
import json

View File

@ -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

View File

@ -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)
register.filter(urlize_quoted_links)

View File

@ -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

View File

@ -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

8
docs/requirements.txt Normal file
View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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',
)

View File

View File

@ -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,))

View File

@ -0,0 +1,6 @@
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('simpleexample.views',
url(r'^$', 'MyModelRootResource'),
url(r'^([0-9]+)/$', 'MyModelResource'),
)

View File

@ -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

View File

@ -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)),
)

View File

@ -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