mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-02 03:13:18 +03:00
Rename to django-rest-framework, get simpleexample working
This commit is contained in:
parent
8a470f031e
commit
42f2f9b40d
20
README.txt
20
README.txt
|
@ -1,17 +1,21 @@
|
||||||
# To install django-rest-framework...
|
# To install django-rest-framework in a virtualenv environment...
|
||||||
#
|
|
||||||
# Requirements:
|
|
||||||
# python2.6
|
|
||||||
# virtualenv
|
|
||||||
|
|
||||||
hg clone https://tomchristie@bitbucket.org/tomchristie/django-rest-framework
|
hg clone https://tomchristie@bitbucket.org/tomchristie/django-rest-framework
|
||||||
cd django-rest-framework/
|
cd django-rest-framework/
|
||||||
virtualenv --no-site-packages --distribute --python=python2.6 env
|
virtualenv --no-site-packages --distribute --python=python2.6 env
|
||||||
source ./env/bin/activate
|
source ./env/bin/activate
|
||||||
pip install -r ./requirements.txt
|
pip install -r requirements.txt
|
||||||
python ./src/manage.py test
|
|
||||||
|
|
||||||
# To build the documentation...
|
# 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
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"""Emitters are used to serialize a Resource's output into specific media types.
|
"""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,
|
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.
|
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.template import RequestContext, loader
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from flywheel.response import NoContent
|
from djangorestframework.response import NoContent
|
||||||
from flywheel.utils import dict2xml, url_resolves
|
from djangorestframework.utils import dict2xml, url_resolves
|
||||||
|
|
||||||
from urllib import quote_plus
|
from urllib import quote_plus
|
||||||
import string
|
import string
|
||||||
|
@ -193,7 +193,7 @@ class XMLEmitter(BaseEmitter):
|
||||||
|
|
||||||
class DocumentingHTMLEmitter(DocumentingTemplateEmitter):
|
class DocumentingHTMLEmitter(DocumentingTemplateEmitter):
|
||||||
"""Emitter which provides a browsable HTML interface for an API.
|
"""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'
|
media_type = 'text/html'
|
||||||
template = 'emitter.html'
|
template = 'emitter.html'
|
||||||
|
|
|
@ -2,8 +2,8 @@ from django.forms import ModelForm
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
|
|
||||||
from flywheel.response import status, Response, ResponseException
|
from djangorestframework.response import status, Response, ResponseException
|
||||||
from flywheel.resource import Resource
|
from djangorestframework.resource import Resource
|
||||||
|
|
||||||
import decimal
|
import decimal
|
||||||
import inspect
|
import inspect
|
||||||
|
@ -336,28 +336,41 @@ class ModelResource(Resource):
|
||||||
return _any(data, self.fields)
|
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
|
# TODO: test creation on a non-existing resource url
|
||||||
all_kw_args = dict(content.items() + kwargs.items())
|
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()
|
instance.save()
|
||||||
headers = {}
|
headers = {}
|
||||||
if hasattr(instance, 'get_absolute_url'):
|
if hasattr(instance, 'get_absolute_url'):
|
||||||
headers['Location'] = self.add_domain(instance.get_absolute_url())
|
headers['Location'] = self.add_domain(instance.get_absolute_url())
|
||||||
return Response(status.HTTP_201_CREATED, instance, headers)
|
return Response(status.HTTP_201_CREATED, instance, headers)
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, auth, *args, **kwargs):
|
||||||
try:
|
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:
|
except self.model.DoesNotExist:
|
||||||
raise ResponseException(status.HTTP_404_NOT_FOUND)
|
raise ResponseException(status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
return instance
|
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
|
# 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:
|
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():
|
for (key, val) in content.items():
|
||||||
setattr(instance, key, val)
|
setattr(instance, key, val)
|
||||||
except self.model.DoesNotExist:
|
except self.model.DoesNotExist:
|
||||||
|
@ -367,9 +380,14 @@ class ModelResource(Resource):
|
||||||
instance.save()
|
instance.save()
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
def delete(self, request, auth, *args, **kwargs):
|
||||||
try:
|
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:
|
except self.model.DoesNotExist:
|
||||||
raise ResponseException(status.HTTP_404_NOT_FOUND, None, {})
|
raise ResponseException(status.HTTP_404_NOT_FOUND, None, {})
|
||||||
|
|
||||||
|
@ -382,7 +400,7 @@ class RootModelResource(ModelResource):
|
||||||
allowed_methods = ('GET', 'POST')
|
allowed_methods = ('GET', 'POST')
|
||||||
queryset = None
|
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()
|
queryset = self.queryset if self.queryset else self.model.objects.all()
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
@ -396,7 +414,7 @@ class QueryModelResource(ModelResource):
|
||||||
def get_form(self, data=None):
|
def get_form(self, data=None):
|
||||||
return 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()
|
queryset = self.queryset if self.queryset else self.model.objects.all()
|
||||||
return queryset
|
return queryset
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from flywheel.response import status, ResponseException
|
from djangorestframework.response import status, ResponseException
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import json
|
import json
|
|
@ -2,8 +2,8 @@ from django.contrib.sites.models import Site
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
|
||||||
from flywheel import emitters, parsers, authenticators
|
from djangorestframework import emitters, parsers, authenticators
|
||||||
from flywheel.response import status, Response, ResponseException
|
from djangorestframework.response import status, Response, ResponseException
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
import re
|
import re
|
|
@ -97,4 +97,4 @@ urlize_quoted_links.is_safe = True
|
||||||
# Register urlize_quoted_links as a custom filter
|
# Register urlize_quoted_links as a custom filter
|
||||||
# http://docs.djangoproject.com/en/dev/howto/custom-template-tags/
|
# http://docs.djangoproject.com/en/dev/howto/custom-template-tags/
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
register.filter(urlize_quoted_links)
|
register.filter(urlize_quoted_links)
|
|
@ -14,7 +14,7 @@
|
||||||
import sys, os
|
import sys, os
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
|
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'))
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'examples'))
|
||||||
import settings
|
import settings
|
||||||
from django.core.management import setup_environ
|
from django.core.management import setup_environ
|
||||||
|
|
|
@ -26,10 +26,10 @@ Requirements
|
||||||
Installation & Setup
|
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::
|
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:
|
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.
|
Often you'll want parts of your API to directly map to existing Models.
|
||||||
At it's simplest this looks something like this...
|
At it's simplest this looks something like this...
|
||||||
|
|
||||||
``views.py``::
|
``urls.py``
|
||||||
|
|
||||||
from djangorestframework.modelresource import ModelResource, ModelRootResource
|
.. include:: ../examples/simpleexample/urls.py
|
||||||
from models import MyModel
|
:literal:
|
||||||
|
|
||||||
class MyModelRootResource(ModelRootResource):
|
``views.py``
|
||||||
"""A create/list resource for MyModel."""
|
|
||||||
allowed_methods = ('GET', 'POST')
|
|
||||||
model = MyModel
|
|
||||||
|
|
||||||
class MyModelResource(ModelResource):
|
.. include:: ../examples/simpleexample/views.py
|
||||||
"""A read/update/delete resource for MyModel."""
|
:literal:
|
||||||
allowed_methods = ('GET', 'PUT', 'DELETE')
|
|
||||||
model = MyModel
|
|
||||||
|
|
||||||
``urls.py``::
|
|
||||||
|
|
||||||
urlpatterns += patterns('myapp.views',
|
|
||||||
url(r'^mymodel/$', 'MyModelRootResource'),
|
|
||||||
url(r'^mymodel/([^/]+)/$', 'MyModelResource'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
|
|
8
docs/requirements.txt
Normal file
8
docs/requirements.txt
Normal 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
|
|
@ -1,6 +1,6 @@
|
||||||
from flywheel.response import Response, status
|
from djangorestframework.response import Response, status
|
||||||
from flywheel.resource import Resource
|
from djangorestframework.resource import Resource
|
||||||
from flywheel.modelresource import ModelResource, RootModelResource
|
from djangorestframework.modelresource import ModelResource, RootModelResource
|
||||||
from blogpost.models import BlogPost, Comment
|
from blogpost.models import BlogPost, Comment
|
||||||
|
|
||||||
BLOG_POST_FIELDS = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url')
|
BLOG_POST_FIELDS = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url')
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from flywheel.resource import Resource
|
from djangorestframework.resource import Resource
|
||||||
from flywheel.response import Response, status
|
from djangorestframework.response import Response, status
|
||||||
|
|
||||||
import pickle
|
import pickle
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from flywheel.resource import Resource
|
from djangorestframework.resource import Resource
|
||||||
from flywheel.response import Response, status
|
from djangorestframework.response import Response, status
|
||||||
from flywheel.emitters import BaseEmitter
|
from djangorestframework.emitters import BaseEmitter
|
||||||
|
|
||||||
from pygments.formatters import HtmlFormatter
|
from pygments.formatters import HtmlFormatter
|
||||||
from pygments.lexers import get_lexer_by_name
|
from pygments.lexers import get_lexer_by_name
|
||||||
|
|
6
examples/requirements.txt
Normal file
6
examples/requirements.txt
Normal 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
|
|
@ -93,9 +93,10 @@ INSTALLED_APPS = (
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.sites',
|
'django.contrib.sites',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.admin',
|
#'django.contrib.admin',
|
||||||
'flywheel',
|
'djangorestframework',
|
||||||
'blogpost',
|
'simpleexample',
|
||||||
'objectstore',
|
'objectstore',
|
||||||
'pygments_api'
|
'pygments_api',
|
||||||
|
'blogpost',
|
||||||
)
|
)
|
||||||
|
|
0
examples/simpleexample/__init__.py
Normal file
0
examples/simpleexample/__init__.py
Normal file
23
examples/simpleexample/models.py
Normal file
23
examples/simpleexample/models.py
Normal 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,))
|
||||||
|
|
6
examples/simpleexample/urls.py
Normal file
6
examples/simpleexample/urls.py
Normal 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'),
|
||||||
|
)
|
18
examples/simpleexample/views.py
Normal file
18
examples/simpleexample/views.py
Normal 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
|
|
@ -1,14 +1,27 @@
|
||||||
from django.conf.urls.defaults import patterns, include
|
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('',
|
urlpatterns = patterns('',
|
||||||
(r'^pygments-example/', include('pygments_api.urls')),
|
(r'^$', RootResource),
|
||||||
(r'^blog-post-example/', include('blogpost.urls')),
|
(r'^simple-example/', include('simpleexample.urls')),
|
||||||
(r'^object-store-example/', include('objectstore.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/login/$', 'django.contrib.auth.views.login'),
|
||||||
(r'^accounts/logout/$', 'django.contrib.auth.views.logout'),
|
(r'^accounts/logout/$', 'django.contrib.auth.views.logout'),
|
||||||
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
#(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
(r'^admin/', include(admin.site.urls)),
|
#(r'^admin/', include(admin.site.urls)),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# Django and pip are required if installing into a virtualenv environment...
|
||||||
|
|
||||||
Django==1.2.4
|
Django==1.2.4
|
||||||
distribute==0.6.14
|
distribute==0.6.14
|
||||||
wsgiref==0.1.2
|
wsgiref==0.1.2
|
||||||
|
|
Loading…
Reference in New Issue
Block a user