emitters -> renderers

This commit is contained in:
Tom Christie 2011-05-02 19:49:12 +01:00
parent b358fbdbe9
commit 8756664e06
8 changed files with 111 additions and 101 deletions

View File

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

View File

@ -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
pass
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)
http_method_names = ['get', 'head', 'options', 'trace', 'patch']
class ListModelResource(ListModelMixin, ModelResource):
"""Resource with default operations for list."""
pass

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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