aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Christie2011-05-02 19:49:12 +0100
committerTom Christie2011-05-02 19:49:12 +0100
commit8756664e064a18afc4713d921c318cd968f18433 (patch)
tree8eb4499900552963f88972d0853e68d05159295f
parentb358fbdbe9cbd4ce644c4b2c7b9b4cec0811e14e (diff)
downloaddjango-rest-framework-8756664e064a18afc4713d921c318cd968f18433.tar.bz2
emitters -> renderers
-rw-r--r--djangorestframework/mixins.py90
-rw-r--r--djangorestframework/modelresource.py94
-rw-r--r--djangorestframework/renderers.py2
-rw-r--r--djangorestframework/resource.py10
-rw-r--r--examples/blogpost/models.py5
-rw-r--r--examples/blogpost/views.py7
-rw-r--r--examples/mixin/urls.py2
-rw-r--r--examples/pygments_api/views.py2
8 files changed, 111 insertions, 101 deletions
diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py
index ebeee31a..6bd83bfa 100644
--- a/djangorestframework/mixins.py
+++ b/djangorestframework/mixins.py
@@ -6,6 +6,7 @@ from djangorestframework import status
from django.http import HttpResponse
from django.http.multipartparser import LimitBytes # TODO: Use LimitedStream in compat
+
from StringIO import StringIO
from decimal import Decimal
import re
@@ -233,7 +234,7 @@ class RequestMixin(object):
@property
def default_parser(self):
- """Return the view's most preffered renderer.
+ """Return the view's most preferred renderer.
(This has no behavioural effect, but is may be used by documenting renderers)"""
return self.parsers[0]
@@ -437,3 +438,90 @@ class AuthMixin(object):
'You may need to login or otherwise authenticate the request.'})
+########## Model Mixins ##########
+
+class ReadModelMixin(object):
+ """Behaviour to read a model instance on GET requests"""
+ def get(self, request, *args, **kwargs):
+ try:
+ 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 ErrorResponse(status.HTTP_404_NOT_FOUND)
+
+ return instance
+
+
+class CreateModelMixin(object):
+ """Behaviour to create a model instance on POST requests"""
+ def post(self, request, *args, **kwargs):
+ # translated 'related_field' kwargs into 'related_field_id'
+ for related_name in [field.name for field in self.model._meta.fields if isinstance(field, RelatedField)]:
+ if kwargs.has_key(related_name):
+ kwargs[related_name + '_id'] = kwargs[related_name]
+ del kwargs[related_name]
+
+ all_kw_args = dict(self.CONTENT.items() + kwargs.items())
+ 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'] = instance.get_absolute_url()
+ return Response(status.HTTP_201_CREATED, instance, headers)
+
+
+class UpdateModelMixin(object):
+ """Behaviour to update a model instance on PUT requests"""
+ def put(self, request, *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:
+ 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 self.CONTENT.items():
+ setattr(instance, key, val)
+ except self.model.DoesNotExist:
+ instance = self.model(**self.CONTENT)
+ instance.save()
+
+ instance.save()
+ return instance
+
+
+class DeleteModelMixin(object):
+ """Behaviour to delete a model instance on DELETE requests"""
+ def delete(self, request, *args, **kwargs):
+ try:
+ 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 ErrorResponse(status.HTTP_404_NOT_FOUND, None, {})
+
+ instance.delete()
+ return
+
+
+class ListModelMixin(object):
+ """Behaviour to list a set of model instances on GET requests"""
+ queryset = None
+
+ def get(self, request, *args, **kwargs):
+ queryset = self.queryset if self.queryset else self.model.objects.all()
+ return queryset.filter(**kwargs)
+
+
diff --git a/djangorestframework/modelresource.py b/djangorestframework/modelresource.py
index c61cc375..c286e586 100644
--- a/djangorestframework/modelresource.py
+++ b/djangorestframework/modelresource.py
@@ -341,94 +341,16 @@ class ModelResource(Resource):
return _any(data, self.fields)
- def get(self, request, *args, **kwargs):
- try:
- 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 ErrorResponse(status.HTTP_404_NOT_FOUND)
-
- return instance
-
- def post(self, request, *args, **kwargs):
- # TODO: test creation on a non-existing resource url
-
- # translated related_field into related_field_id
- for related_name in [field.name for field in self.model._meta.fields if isinstance(field, RelatedField)]:
- if kwargs.has_key(related_name):
- kwargs[related_name + '_id'] = kwargs[related_name]
- del kwargs[related_name]
-
- all_kw_args = dict(self.CONTENT.items() + kwargs.items())
- 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'] = instance.get_absolute_url()
- return Response(status.HTTP_201_CREATED, instance, headers)
-
- def put(self, request, *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:
- 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 self.CONTENT.items():
- setattr(instance, key, val)
- except self.model.DoesNotExist:
- instance = self.model(**self.CONTENT)
- instance.save()
-
- instance.save()
- return instance
-
- def delete(self, request, *args, **kwargs):
- try:
- 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 ErrorResponse(status.HTTP_404_NOT_FOUND, None, {})
-
- instance.delete()
- return
-class InstanceModelResource(ModelResource):
- http_method_names = ['get', 'put', 'delete', 'head', 'options', 'trace', 'patch'] # Bit of a hack, these - needs fixing.
+class InstanceModelResource(ReadModelMixin, UpdateModelMixin, DeleteModelMixin, ModelResource):
+ """A view which provides default operations for read/update/delete against a model instance."""
+ pass
-class RootModelResource(ModelResource):
+class ListOrCreateModelResource(CreateModelMixin, ListModelMixin, ModelResource):
"""A Resource which provides default operations for list and create."""
- queryset = None
-
- def get(self, request, *args, **kwargs):
- queryset = self.queryset if self.queryset else self.model.objects.all()
- return queryset.filter(**kwargs)
-
- http_method_names = ['get', 'post', 'head', 'options', 'trace', 'patch']
-
-class QueryModelResource(ModelResource):
- """Resource with default operations for list.
- TODO: provide filter/order/num_results/paging, and a create operation to create queries."""
- allowed_methods = ('GET',)
- queryset = None
-
- def get(self, request, *args, **kwargs):
- queryset = self.queryset if self.queryset else self.model.objects.all()
- return queryset.filer(**kwargs)
+ pass
- http_method_names = ['get', 'head', 'options', 'trace', 'patch']
+class ListModelResource(ListModelMixin, ModelResource):
+ """Resource with default operations for list."""
+ pass \ No newline at end of file
diff --git a/djangorestframework/renderers.py b/djangorestframework/renderers.py
index e53dc061..2a07894e 100644
--- a/djangorestframework/renderers.py
+++ b/djangorestframework/renderers.py
@@ -43,7 +43,7 @@ class BaseRenderer(object):
class TemplateRenderer(BaseRenderer):
"""Provided for convienience.
- Emit the output by simply rendering it with the given template."""
+ Render the output by simply rendering it with the given template."""
media_type = None
template = None
diff --git a/djangorestframework/resource.py b/djangorestframework/resource.py
index 7879da7c..e06873ae 100644
--- a/djangorestframework/resource.py
+++ b/djangorestframework/resource.py
@@ -19,14 +19,12 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View):
"""Handles incoming requests and maps them to REST operations.
Performs request deserialization, response serialization, authentication and input validation."""
- http_method_names = ['get', 'post', 'put', 'delete', 'head', 'options', 'trace', 'patch']
-
# List of renderers the resource can serialize the response with, ordered by preference.
renderers = ( renderers.JSONRenderer,
- renderers.DocumentingHTMLRenderer,
- renderers.DocumentingXHTMLRenderer,
- renderers.DocumentingPlainTextRenderer,
- renderers.XMLRenderer )
+ renderers.DocumentingHTMLRenderer,
+ renderers.DocumentingXHTMLRenderer,
+ renderers.DocumentingPlainTextRenderer,
+ renderers.XMLRenderer )
# List of parsers the resource can parse the request with.
parsers = ( parsers.JSONParser,
diff --git a/examples/blogpost/models.py b/examples/blogpost/models.py
index 01a91e15..3489c596 100644
--- a/examples/blogpost/models.py
+++ b/examples/blogpost/models.py
@@ -12,6 +12,8 @@ RATING_CHOICES = ((0, 'Awful'),
(3, 'Good'),
(4, 'Excellent'))
+MAX_POSTS = 10
+
class BlogPost(models.Model):
key = models.CharField(primary_key=True, max_length=64, default=uuid_str, editable=False)
title = models.CharField(max_length=128)
@@ -38,9 +40,10 @@ class BlogPost(models.Model):
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(self.__class__, self).save(*args, **kwargs)
- for obj in self.__class__.objects.order_by('-pk')[10:]:
+ for obj in self.__class__.objects.order_by('-pk')[MAX_POSTS:]:
obj.delete()
+
class Comment(models.Model):
blogpost = models.ForeignKey(BlogPost, editable=False, related_name='comments')
username = models.CharField(max_length=128)
diff --git a/examples/blogpost/views.py b/examples/blogpost/views.py
index e47f4a5b..c4b54f73 100644
--- a/examples/blogpost/views.py
+++ b/examples/blogpost/views.py
@@ -1,12 +1,11 @@
-from djangorestframework.modelresource import InstanceModelResource, RootModelResource
+from djangorestframework.modelresource import InstanceModelResource, ListOrCreateModelResource
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')
-MAX_POSTS = 10
-class BlogPosts(RootModelResource):
+class BlogPosts(ListOrCreateModelResource):
"""A resource with which lists all existing blog posts and creates new blog posts."""
model = models.BlogPost
fields = BLOG_POST_FIELDS
@@ -16,7 +15,7 @@ class BlogPostInstance(InstanceModelResource):
model = models.BlogPost
fields = BLOG_POST_FIELDS
-class Comments(RootModelResource):
+class Comments(ListOrCreateModelResource):
"""A resource which lists all existing comments for a given blog post, and creates new blog comments for a given blog post."""
model = models.Comment
fields = COMMENT_FIELDS
diff --git a/examples/mixin/urls.py b/examples/mixin/urls.py
index f4300f41..1d25f6c7 100644
--- a/examples/mixin/urls.py
+++ b/examples/mixin/urls.py
@@ -15,7 +15,7 @@ class ExampleView(ResponseMixin, View):
def get(self, request):
response = Response(200, {'description': 'Some example content',
'url': reverse('mixin-view')})
- return self.emit(response)
+ return self.render(response)
urlpatterns = patterns('',
diff --git a/examples/pygments_api/views.py b/examples/pygments_api/views.py
index 278e8250..253b0907 100644
--- a/examples/pygments_api/views.py
+++ b/examples/pygments_api/views.py
@@ -68,7 +68,7 @@ class PygmentsRoot(Resource):
class PygmentsInstance(Resource):
"""Simply return the stored highlighted HTML file with the correct mime type.
- This Resource only emits HTML and uses a standard HTML renderer rather than the renderers.DocumentingHTMLRenderer class."""
+ This Resource only renders HTML and uses a standard HTML renderer rather than the renderers.DocumentingHTMLRenderer class."""
renderers = (HTMLRenderer,)
def get(self, request, unique_id):