Commit 8756664e by Tom Christie

emitters -> renderers

parent b358fbdb
...@@ -6,6 +6,7 @@ from djangorestframework import status ...@@ -6,6 +6,7 @@ from djangorestframework import status
from django.http import HttpResponse from django.http import HttpResponse
from django.http.multipartparser import LimitBytes # TODO: Use LimitedStream in compat from django.http.multipartparser import LimitBytes # TODO: Use LimitedStream in compat
from StringIO import StringIO from StringIO import StringIO
from decimal import Decimal from decimal import Decimal
import re import re
...@@ -233,7 +234,7 @@ class RequestMixin(object): ...@@ -233,7 +234,7 @@ class RequestMixin(object):
@property @property
def default_parser(self): 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)""" (This has no behavioural effect, but is may be used by documenting renderers)"""
return self.parsers[0] return self.parsers[0]
...@@ -437,3 +438,90 @@ class AuthMixin(object): ...@@ -437,3 +438,90 @@ class AuthMixin(object):
'You may need to login or otherwise authenticate the request.'}) '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)
...@@ -341,94 +341,16 @@ class ModelResource(Resource): ...@@ -341,94 +341,16 @@ class ModelResource(Resource):
return _any(data, self.fields) 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() class InstanceModelResource(ReadModelMixin, UpdateModelMixin, DeleteModelMixin, ModelResource):
return """A view which provides default operations for read/update/delete against a model instance."""
pass
class ListOrCreateModelResource(CreateModelMixin, ListModelMixin, ModelResource):
class InstanceModelResource(ModelResource):
http_method_names = ['get', 'put', 'delete', 'head', 'options', 'trace', 'patch'] # Bit of a hack, these - needs fixing.
class RootModelResource(ModelResource):
"""A Resource which provides default operations for list and create.""" """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
\ No newline at end of file
...@@ -43,7 +43,7 @@ class BaseRenderer(object): ...@@ -43,7 +43,7 @@ class BaseRenderer(object):
class TemplateRenderer(BaseRenderer): class TemplateRenderer(BaseRenderer):
"""Provided for convienience. """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 media_type = None
template = None template = None
......
...@@ -19,8 +19,6 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View): ...@@ -19,8 +19,6 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View):
"""Handles incoming requests and maps them to REST operations. """Handles incoming requests and maps them to REST operations.
Performs request deserialization, response serialization, authentication and input validation.""" 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. # List of renderers the resource can serialize the response with, ordered by preference.
renderers = ( renderers.JSONRenderer, renderers = ( renderers.JSONRenderer,
renderers.DocumentingHTMLRenderer, renderers.DocumentingHTMLRenderer,
......
...@@ -12,6 +12,8 @@ RATING_CHOICES = ((0, 'Awful'), ...@@ -12,6 +12,8 @@ RATING_CHOICES = ((0, 'Awful'),
(3, 'Good'), (3, 'Good'),
(4, 'Excellent')) (4, 'Excellent'))
MAX_POSTS = 10
class BlogPost(models.Model): class BlogPost(models.Model):
key = models.CharField(primary_key=True, max_length=64, default=uuid_str, editable=False) key = models.CharField(primary_key=True, max_length=64, default=uuid_str, editable=False)
title = models.CharField(max_length=128) title = models.CharField(max_length=128)
...@@ -38,9 +40,10 @@ class BlogPost(models.Model): ...@@ -38,9 +40,10 @@ class BlogPost(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.slug = slugify(self.title) self.slug = slugify(self.title)
super(self.__class__, self).save(*args, **kwargs) 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() obj.delete()
class Comment(models.Model): class Comment(models.Model):
blogpost = models.ForeignKey(BlogPost, editable=False, related_name='comments') blogpost = models.ForeignKey(BlogPost, editable=False, related_name='comments')
username = models.CharField(max_length=128) username = models.CharField(max_length=128)
......
from djangorestframework.modelresource import InstanceModelResource, RootModelResource from djangorestframework.modelresource import InstanceModelResource, ListOrCreateModelResource
from blogpost import models from blogpost import models
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')
COMMENT_FIELDS = ('username', 'comment', 'created', 'rating', 'absolute_url', 'blogpost_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.""" """A resource with which lists all existing blog posts and creates new blog posts."""
model = models.BlogPost model = models.BlogPost
fields = BLOG_POST_FIELDS fields = BLOG_POST_FIELDS
...@@ -16,7 +15,7 @@ class BlogPostInstance(InstanceModelResource): ...@@ -16,7 +15,7 @@ class BlogPostInstance(InstanceModelResource):
model = models.BlogPost model = models.BlogPost
fields = BLOG_POST_FIELDS 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.""" """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 model = models.Comment
fields = COMMENT_FIELDS fields = COMMENT_FIELDS
......
...@@ -15,7 +15,7 @@ class ExampleView(ResponseMixin, View): ...@@ -15,7 +15,7 @@ class ExampleView(ResponseMixin, View):
def get(self, request): def get(self, request):
response = Response(200, {'description': 'Some example content', response = Response(200, {'description': 'Some example content',
'url': reverse('mixin-view')}) 'url': reverse('mixin-view')})
return self.emit(response) return self.render(response)
urlpatterns = patterns('', urlpatterns = patterns('',
......
...@@ -68,7 +68,7 @@ class PygmentsRoot(Resource): ...@@ -68,7 +68,7 @@ class PygmentsRoot(Resource):
class PygmentsInstance(Resource): class PygmentsInstance(Resource):
"""Simply return the stored highlighted HTML file with the correct mime type. """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,) renderers = (HTMLRenderer,)
def get(self, request, unique_id): def get(self, request, unique_id):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment