Commit 42825e44 by Tom Christie

Sample example working

parent 95ac2396
...@@ -18,7 +18,7 @@ class TemplatedEmitter(BaseEmitter): ...@@ -18,7 +18,7 @@ class TemplatedEmitter(BaseEmitter):
template = None template = None
def emit(self, output): def emit(self, output):
content = json.dumps(output, indent=4) content = json.dumps(output, indent=4, sort_keys=True)
template = loader.get_template(self.template) template = loader.get_template(self.template)
context = RequestContext(self.request, { context = RequestContext(self.request, {
'content': content, 'content': content,
......
...@@ -137,15 +137,20 @@ class Resource(object): ...@@ -137,15 +137,20 @@ class Resource(object):
def determine_form(self, data=None): def determine_form(self, input_data=None, return_data=None):
"""Optionally return a Django Form instance, which may be used for validation """Optionally return a Django Form instance, which may be used for validation
and/or rendered by an HTML/XHTML emitter. and/or rendered by an HTML/XHTML emitter.
The data argument will be non Null if the form is required to be bound to some deserialized The input_data or return_data arguments can be used to bind the form either to the deserialized input,
input data, or Null if the form is required to be unbound. or to a return object.
""" """
if self.form: if self.form:
return self.form(data) if input_data:
return self.form(input_data)
elif return_data:
return self.form(return_data)
else:
return self.form()
return None return None
...@@ -259,12 +264,13 @@ class Resource(object): ...@@ -259,12 +264,13 @@ class Resource(object):
if method in ('PUT', 'POST'): if method in ('PUT', 'POST'):
parser = self.determine_parser(request) parser = self.determine_parser(request)
data = parser(self, request).parse(request.raw_post_data) data = parser(self, request).parse(request.raw_post_data)
form = self.determine_form(data) form = self.determine_form(input_data=data)
data = self.cleanup_request(data, form) data = self.cleanup_request(data, form)
(status, ret, headers) = func(data, request.META, *args, **kwargs) (status, ret, headers) = func(data, request.META, *args, **kwargs)
else: else:
(status, ret, headers) = func(request.META, *args, **kwargs) (status, ret, headers) = func(request.META, *args, **kwargs)
form = self.determine_form(return_data=ret)
except ResourceException, exc: except ResourceException, exc:
...@@ -274,7 +280,7 @@ class Resource(object): ...@@ -274,7 +280,7 @@ class Resource(object):
if emitter is None: if emitter is None:
mimetype, emitter = self.emitters[0] mimetype, emitter = self.emitters[0]
# Use a form unbound to any data if one has not yet been created # Create an unbound form if one has not yet been created
if form is None: if form is None:
form = self.determine_form() form = self.determine_form()
...@@ -284,7 +290,6 @@ class Resource(object): ...@@ -284,7 +290,6 @@ class Resource(object):
# Serialize the response content # Serialize the response content
ret = self.cleanup_response(ret) ret = self.cleanup_response(ret)
content = emitter(self, request, status, headers, form).emit(ret) content = emitter(self, request, status, headers, form).emit(ret)
print content
# Build the HTTP Response # Build the HTTP Response
resp = HttpResponse(content, mimetype=mimetype, status=status) resp = HttpResponse(content, mimetype=mimetype, status=status)
...@@ -308,7 +313,7 @@ class ModelResource(Resource): ...@@ -308,7 +313,7 @@ class ModelResource(Resource):
fields = None fields = None
form_fields = None form_fields = None
def determine_form(self, data=None): def determine_form(self, input_data=None, return_data=None):
"""Return a form that may be used in validation and/or rendering an html emitter""" """Return a form that may be used in validation and/or rendering an html emitter"""
if self.form: if self.form:
return self.form return self.form
...@@ -317,12 +322,14 @@ class ModelResource(Resource): ...@@ -317,12 +322,14 @@ class ModelResource(Resource):
class NewModelForm(ModelForm): class NewModelForm(ModelForm):
class Meta: class Meta:
model = self.model model = self.model
fields = self.form_fields if self.form_fields else self.fields fields = self.form_fields if self.form_fields else None #self.fields
if data is None: if input_data:
return NewModelForm() return NewModelForm(input_data)
elif return_data:
return NewModelForm(instance=return_data)
else: else:
return NewModelForm(data) return NewModelForm()
else: else:
return None return None
...@@ -359,6 +366,12 @@ class ModelResource(Resource): ...@@ -359,6 +366,12 @@ class ModelResource(Resource):
ret = _list(thing) ret = _list(thing)
elif isinstance(thing, dict): elif isinstance(thing, dict):
ret = _dict(thing) ret = _dict(thing)
elif isinstance(thing, int):
ret = thing
elif isinstance(thing, bool):
ret = thing
elif isinstance(thing, type(None)):
ret = thing
elif isinstance(thing, decimal.Decimal): elif isinstance(thing, decimal.Decimal):
ret = str(thing) ret = str(thing)
elif isinstance(thing, Model): elif isinstance(thing, Model):
...@@ -417,7 +430,7 @@ class ModelResource(Resource): ...@@ -417,7 +430,7 @@ class ModelResource(Resource):
ret = { } ret = { }
#handler = self.in_typemapper(type(data), self.anonymous) # TRC #handler = self.in_typemapper(type(data), self.anonymous) # TRC
handler = None # TRC handler = None # TRC
get_absolute_uri = False get_absolute_url = False
if handler or fields: if handler or fields:
v = lambda f: getattr(data, f.attname) v = lambda f: getattr(data, f.attname)
...@@ -444,12 +457,13 @@ class ModelResource(Resource): ...@@ -444,12 +457,13 @@ class ModelResource(Resource):
for field in get_fields.copy(): for field in get_fields.copy():
if exclude.match(field): if exclude.match(field):
get_fields.discard(field) get_fields.discard(field)
get_absolute_url = True
else: else:
get_fields = set(fields) get_fields = set(fields)
if 'absolute_url' in get_fields: # MOVED (TRC)
if 'absolute_uri' in get_fields: # MOVED (TRC) get_absolute_url = True
get_absolute_uri = True
met_fields = _method_fields(handler, get_fields) # TRC met_fields = _method_fields(handler, get_fields) # TRC
...@@ -508,14 +522,37 @@ class ModelResource(Resource): ...@@ -508,14 +522,37 @@ class ModelResource(Resource):
# ret[maybe_field] = _any(handler_f(data)) # ret[maybe_field] = _any(handler_f(data))
else: else:
# Add absolute_url if it exists
get_absolute_url = True
# Add all the fields
for f in data._meta.fields: for f in data._meta.fields:
ret[f.attname] = _any(getattr(data, f.attname)) if f.attname != 'id':
ret[f.attname] = _any(getattr(data, f.attname))
fields = dir(data.__class__) + ret.keys() # Add all the propertiess
add_ons = [k for k in dir(data) if k not in fields] klass = data.__class__
for attr in dir(klass):
if not attr.startswith('_') and not attr in ('pk','id') and isinstance(getattr(klass, attr, None), property):
#if attr.endswith('_url') or attr.endswith('_uri'):
# ret[attr] = self.make_absolute(_any(getattr(data, attr)))
#else:
ret[attr] = _any(getattr(data, attr))
#fields = dir(data.__class__) + ret.keys()
#add_ons = [k for k in dir(data) if k not in fields and not k.startswith('_')]
#print add_ons
###print dir(data.__class__)
#from django.db.models import Model
#model_fields = dir(Model)
#for attr in dir(data):
## #if attr.startswith('_'):
## # continue
# if (attr in fields) and not (attr in model_fields) and not attr.startswith('_'):
# print attr, type(getattr(data, attr, None)), attr in fields, attr in model_fields
for k in add_ons: #for k in add_ons:
ret[k] = _any(getattr(data, k)) # ret[k] = _any(getattr(data, k))
# TRC # TRC
# resouce uri # resouce uri
...@@ -532,9 +569,13 @@ class ModelResource(Resource): ...@@ -532,9 +569,13 @@ class ModelResource(Resource):
# except: pass # except: pass
# absolute uri # absolute uri
if hasattr(data, 'get_absolute_url') and get_absolute_uri: if hasattr(data, 'get_absolute_url') and get_absolute_url:
try: ret['absolute_uri'] = self.make_absolute(data.get_absolute_url()) try: ret['absolute_url'] = self.make_absolute(data.get_absolute_url())
except: pass except: pass
for key, val in ret.items():
if key.endswith('_url') or key.endswith('_uri'):
ret[key] = self.make_absolute(val)
return ret return ret
...@@ -560,8 +601,9 @@ class ModelResource(Resource): ...@@ -560,8 +601,9 @@ class ModelResource(Resource):
return _any(data, self.fields) return _any(data, self.fields)
def create(self, data, headers={}): def create(self, data, headers={}, *args, **kwargs):
instance = self.model(**data) all_kw_args = dict(data.items() + kwargs.items())
instance = self.model(**all_kw_args)
instance.save() instance.save()
headers = {} headers = {}
if hasattr(instance, 'get_absolute_url'): if hasattr(instance, 'get_absolute_url'):
...@@ -569,17 +611,37 @@ class ModelResource(Resource): ...@@ -569,17 +611,37 @@ class ModelResource(Resource):
return (201, instance, headers) return (201, instance, headers)
def read(self, headers={}, *args, **kwargs): def read(self, headers={}, *args, **kwargs):
instance = self.model.objects.get(**kwargs) try:
instance = self.model.objects.get(**kwargs)
except self.model.DoesNotExist:
return (404, '', {})
return (200, instance, {}) return (200, instance, {})
def update(self, data, headers={}, *args, **kwargs): def update(self, data, headers={}, *args, **kwargs):
instance = self.model.objects.get(**kwargs) try:
for (key, val) in data.items(): instance = self.model.objects.get(**kwargs)
setattr(instance, key, val) for (key, val) in data.items():
setattr(instance, key, val)
except self.model.DoesNotExist:
instance = self.model(**data)
instance.save()
instance.save() instance.save()
return (200, instance, {}) return (200, instance, {})
def delete(self, headers={}, *args, **kwargs): def delete(self, headers={}, *args, **kwargs):
instance = self.model.objects.get(**kwargs) instance = self.model.objects.get(**kwargs)
instance.delete() instance.delete()
return (204, '', {}) return (204, '', {})
\ No newline at end of file
class QueryModelResource(ModelResource):
allowed_methods = ('read',)
def determine_form(self, input_data=None, return_data=None):
return None
def read(self, headers={}, *args, **kwargs):
query = self.model.objects.all()
return (200, query, {})
...@@ -11,10 +11,10 @@ ...@@ -11,10 +11,10 @@
<body> <body>
<h1>{{ resource_name }}</h1> <h1>{{ resource_name }}</h1>
<p>{{ resource_doc }}</p> <p>{{ resource_doc }}</p>
<pre>{% autoescape off %}<b>{{ status }} {{ reason }}</b> <pre><b>{{ status }} {{ reason }}</b>{% autoescape off %}
{% for key, val in headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }} {% for key, val in headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
{% endfor %} {% endfor %}
{{ content|urlize_quoted_links }}{% endautoescape %} </pre> {{ content|urlize_quoted_links }} </pre>{% endautoescape %}
{% if 'read' in resource.allowed_operations %} {% if 'read' in resource.allowed_operations %}
<div class='action'> <div class='action'>
......
...@@ -33,7 +33,7 @@ html_gunk_re = re.compile(r'(?:<br clear="all">|<i><\/i>|<b><\/b>|<em><\/em>|<st ...@@ -33,7 +33,7 @@ html_gunk_re = re.compile(r'(?:<br clear="all">|<i><\/i>|<b><\/b>|<em><\/em>|<st
hard_coded_bullets_re = re.compile(r'((?:<p>(?:%s).*?[a-zA-Z].*?</p>\s*)+)' % '|'.join([re.escape(x) for x in DOTS]), re.DOTALL) hard_coded_bullets_re = re.compile(r'((?:<p>(?:%s).*?[a-zA-Z].*?</p>\s*)+)' % '|'.join([re.escape(x) for x in DOTS]), re.DOTALL)
trailing_empty_content_re = re.compile(r'(?:<p>(?:&nbsp;|\s|<br \/>)*?</p>\s*)+\Z') trailing_empty_content_re = re.compile(r'(?:<p>(?:&nbsp;|\s|<br \/>)*?</p>\s*)+\Z')
def urlize_quoted_links(text, trim_url_limit=None, nofollow=False, autoescape=False): def urlize_quoted_links(text, trim_url_limit=None, nofollow=False, autoescape=True):
""" """
Converts any URLs in text into clickable links. Converts any URLs in text into clickable links.
...@@ -90,6 +90,10 @@ def urlize_quoted_links(text, trim_url_limit=None, nofollow=False, autoescape=Fa ...@@ -90,6 +90,10 @@ def urlize_quoted_links(text, trim_url_limit=None, nofollow=False, autoescape=Fa
words[i] = escape(word) words[i] = escape(word)
return u''.join(words) return u''.join(words)
#urlize_quoted_links.needs_autoescape = True
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()
......
from django.db import models from django.db import models
from django.template.defaultfilters import slugify from django.template.defaultfilters import slugify
from datetime import datetime
import uuid import uuid
def uuid_str(): def uuid_str():
return str(uuid.uuid1()) return str(uuid.uuid1())
class ExampleModel(models.Model): #class ExampleModel(models.Model):
num = models.IntegerField(default=2, choices=((1,'one'), (2, 'two'))) # num = models.IntegerField(default=2, choices=((1,'one'), (2, 'two')))
hidden_num = models.IntegerField(verbose_name='Something', help_text='HELP') # hidden_num = models.IntegerField(verbose_name='Something', help_text='HELP')
text = models.TextField(blank=False) # text = models.TextField(blank=False)
another = models.CharField(max_length=10) # another = models.CharField(max_length=10)
class ExampleContainer(models.Model): #class ExampleContainer(models.Model):
"""Container. Has a key, a name, and some internal data, and contains a set of items.""" # """Container. Has a key, a name, and some internal data, and contains a set of items."""
key = models.CharField(primary_key=True, default=uuid_str, max_length=36, editable=False) # key = models.CharField(primary_key=True, default=uuid_str, max_length=36, editable=False)
name = models.CharField(max_length=256) # name = models.CharField(max_length=256)
internal = models.IntegerField(default=0) # internal = models.IntegerField(default=0)
# @models.permalink
# def get_absolute_url(self):
# return ('testapp.views.ContainerInstance', [self.key])
@models.permalink
def get_absolute_url(self):
return ('testapp.views.ContainerInstance', [self.key])
#class ExampleItem(models.Model):
# """Item. Belongs to a container and has an index number and a note.
# Items are uniquely identified by their container and index number."""
# container = models.ForeignKey(ExampleContainer, related_name='items')
# index = models.IntegerField()
# note = models.CharField(max_length=1024)
# unique_together = (container, index)
class ExampleItem(models.Model):
"""Item. Belongs to a container and has an index number and a note.
Items are uniquely identified by their container and index number."""
container = models.ForeignKey(ExampleContainer, related_name='items')
index = models.IntegerField()
note = models.CharField(max_length=1024)
unique_together = (container, index)
RATING_CHOICES = ((0, 'Awful'),
(1, 'Poor'),
(2, 'OK'),
(3, 'Good'),
(4, 'Excellent'))
class BlogPost(models.Model): class BlogPost(models.Model):
slug = models.SlugField(editable=False, primary_key=True, default='blah') 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, help_text='The article title (Required)')
content = models.TextField() content = models.TextField(help_text='The article body (Required)')
when = models.DateTimeField(editable=False) created = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(editable=False, default='')
class Meta:
ordering = ('created',)
@models.permalink @models.permalink
def get_absolute_url(self): def get_absolute_url(self):
return ('testapp.views.BlogPostInstance', (self.slug,)) return ('testapp.views.BlogPostInstance', (self.key,))
@property
@models.permalink
def comments_url(self):
"""Link to a resource which lists all comments for this blog post."""
return ('testapp.views.CommentList', (self.key,))
@property
@models.permalink
def comment_url(self):
"""Link to a resource which can create a comment for this blog post."""
return ('testapp.views.CommentCreator', (self.key,))
def __unicode__(self):
return self.title
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.slug = slugify(self.title) self.slug = slugify(self.title)
self.when = datetime.now()
super(self.__class__, self).save(*args, **kwargs) super(self.__class__, self).save(*args, **kwargs)
class Comment(models.Model): class Comment(models.Model):
blogpost = models.ForeignKey(BlogPost, related_name='comments') blogpost = models.ForeignKey(BlogPost, editable=False, related_name='comments')
name = models.CharField(max_length=128) username = models.CharField(max_length=128, help_text='Please enter a username (Required)')
content = models.TextField() comment = models.TextField(help_text='Enter your comment here (Required)')
when = models.DateTimeField(auto_now_add=True) rating = models.IntegerField(blank=True, null=True, choices=RATING_CHOICES, help_text='Please rate the blog post (Optional)')
created = models.DateTimeField(auto_now_add=True)
@models.permalink @models.permalink
def get_absolute_url(self): def get_absolute_url(self):
return ('testapp.views.CommentInstance', (self.blogpost.slug, self.id)) return ('testapp.views.CommentInstance', (self.blogpost.key, self.id))
def save(self): @property
self.index = self.blogpost.comments.count() @models.permalink
\ No newline at end of file def blogpost_url(self):
return ('testapp.views.BlogPostInstance', (self.blogpost.key,))
...@@ -2,13 +2,18 @@ from django.conf.urls.defaults import patterns ...@@ -2,13 +2,18 @@ from django.conf.urls.defaults import patterns
urlpatterns = patterns('testapp.views', urlpatterns = patterns('testapp.views',
(r'^$', 'RootResource'), (r'^$', 'RootResource'),
(r'^read-only$', 'ReadOnlyResource'), #(r'^read-only$', 'ReadOnlyResource'),
(r'^write-only$', 'WriteOnlyResource'), #(r'^write-only$', 'WriteOnlyResource'),
(r'^read-write$', 'ReadWriteResource'), #(r'^read-write$', 'ReadWriteResource'),
(r'^model$', 'ModelFormResource'), #(r'^model$', 'ModelFormResource'),
(r'^container$', 'ContainerFactory'), #(r'^container$', 'ContainerFactory'),
(r'^container/((?P<key>[^/]+))$', 'ContainerInstance'), #(r'^container/((?P<key>[^/]+))$', 'ContainerInstance'),
(r'^blogpost/create$', 'BlogPostCreator'), (r'^blog-posts/$', 'BlogPostList'),
(r'^blogposts/(?P<slug>[^/]+)', 'BlogPostInstance'), (r'^blog-post/$', 'BlogPostCreator'),
(r'^blog-post/(?P<key>[^/]+)/$', 'BlogPostInstance'),
(r'^blog-post/(?P<blogpost_id>[^/]+)/comments/$', 'CommentList'),
(r'^blog-post/(?P<blogpost_id>[^/]+)/comment/$', 'CommentCreator'),
(r'^blog-post/(?P<blogpost>[^/]+)/comments/(?P<id>[^/]+)/$', 'CommentInstance'),
) )
from rest.resource import Resource, ModelResource from rest.resource import Resource, ModelResource, QueryModelResource
from testapp.forms import ExampleForm from testapp.models import BlogPost, Comment
from testapp.models import ExampleModel, ExampleContainer, BlogPost, Comment
class RootResource(Resource): class RootResource(Resource):
"""This is my docstring """This is the top level resource for the API.
""" All the sub-resources are discoverable from here."""
allowed_operations = ('read',) allowed_operations = ('read',)
def read(self, headers={}, *args, **kwargs): def read(self, headers={}, *args, **kwargs):
return (200, {'read-only-api': self.reverse(ReadOnlyResource), return (200, {'blog-posts': self.reverse(BlogPostList),
'write-only-api': self.reverse(WriteOnlyResource), 'blog-post': self.reverse(BlogPostCreator)}, {})
'read-write-api': self.reverse(ReadWriteResource),
'model-api': self.reverse(ModelFormResource),
'create-container': self.reverse(ContainerFactory),
'blog-post-creator': self.reverse(BlogPostCreator)}, {})
class ReadOnlyResource(Resource): # Blog Post Resources
"""This is my docstring
"""
allowed_operations = ('read',)
def read(self, headers={}, *args, **kwargs):
return (200, {'ExampleString': 'Example',
'ExampleInt': 1,
'ExampleDecimal': 1.0}, {})
class BlogPostList(QueryModelResource):
"""A resource which lists all existing blog posts."""
allowed_operations = ('read', )
model = BlogPost
class WriteOnlyResource(Resource):
"""This is my docstring
"""
allowed_operations = ('update',)
def update(self, data, headers={}, *args, **kwargs): class BlogPostCreator(ModelResource):
return (200, data, {}) """A resource with which blog posts may be created."""
allowed_operations = ('create',)
model = BlogPost
fields = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url')
class ReadWriteResource(Resource): class BlogPostInstance(ModelResource):
"""A resource which represents a single blog post."""
allowed_operations = ('read', 'update', 'delete') allowed_operations = ('read', 'update', 'delete')
create_form = ExampleForm model = BlogPost
update_form = ExampleForm fields = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url')
class ModelFormResource(ModelResource): # Comment Resources
allowed_operations = ('read', 'update', 'delete')
model = ExampleModel
# Nice things: form validation is applied to any input type class CommentList(QueryModelResource):
# html forms for output """A resource which lists all existing comments for a given blog post."""
# output always serialized nicely allowed_operations = ('read', )
class ContainerFactory(ModelResource): model = Comment
class CommentCreator(ModelResource):
"""A resource with which blog comments may be created for a given blog post."""
allowed_operations = ('create',) allowed_operations = ('create',)
model = ExampleContainer model = Comment
fields = ('absolute_uri', 'name', 'key') fields = ('username', 'comment', 'created', 'rating', 'absolute_url', 'blogpost_url')
form_fields = ('name',)
class ContainerInstance(ModelResource): class CommentInstance(ModelResource):
"""A resource which represents a single comment."""
allowed_operations = ('read', 'update', 'delete') allowed_operations = ('read', 'update', 'delete')
model = ExampleContainer model = Comment
fields = ('absolute_uri', 'name', 'key') fields = ('username', 'comment', 'created', 'rating', 'absolute_url', 'blogpost_url')
form_fields = ('name',)
#
#'read-only-api': self.reverse(ReadOnlyResource),
# 'write-only-api': self.reverse(WriteOnlyResource),
# 'read-write-api': self.reverse(ReadWriteResource),
# 'model-api': self.reverse(ModelFormResource),
# 'create-container': self.reverse(ContainerFactory),
#
#class ReadOnlyResource(Resource):
# """This is my docstring
# """
# allowed_operations = ('read',)
#
# def read(self, headers={}, *args, **kwargs):
# return (200, {'ExampleString': 'Example',
# 'ExampleInt': 1,
# 'ExampleDecimal': 1.0}, {})
#
#
#class WriteOnlyResource(Resource):
# """This is my docstring
# """
# allowed_operations = ('update',)
#
# def update(self, data, headers={}, *args, **kwargs):
# return (200, data, {})
#
#
#class ReadWriteResource(Resource):
# allowed_operations = ('read', 'update', 'delete')
# create_form = ExampleForm
# update_form = ExampleForm
#
#
#class ModelFormResource(ModelResource):
# allowed_operations = ('read', 'update', 'delete')
# model = ExampleModel
#
## Nice things: form validation is applied to any input type
## html forms for output
## output always serialized nicely
#class ContainerFactory(ModelResource):
# allowed_operations = ('create',)
# model = ExampleContainer
# fields = ('absolute_uri', 'name', 'key')
# form_fields = ('name',)
#
#
#class ContainerInstance(ModelResource):
# allowed_operations = ('read', 'update', 'delete')
# model = ExampleContainer
# fields = ('absolute_uri', 'name', 'key')
# form_fields = ('name',)
####################### #######################
class BlogPostCreator(ModelResource):
"""A Resource with which blog posts may be created.
This is distinct from blog post instance so that it is discoverable by the client.
(ie the client doens't need to know how to form a blog post url in order to create a blog post)"""
allowed_operations = ('create',)
model = BlogPost
class BlogPostInstance(ModelResource):
"""Represents a single Blog Post."""
allowed_operations = ('read', 'update', 'delete')
model = BlogPost
\ No newline at end of file
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