Commit b0ce3f92 by Tom Christie

Added formats, various form improvements, more refactoring/cleanup

parent 764fbe33
......@@ -3,6 +3,8 @@ import json
from utils import dict2xml
class BaseEmitter(object):
uses_forms = False
def __init__(self, resource):
self.resource = resource
......@@ -24,11 +26,14 @@ class TemplatedEmitter(BaseEmitter):
'resource': self.resource,
})
ret = template.render(context)
# Munge DELETE Response code to allow us to return content
# (Do this *after* we've rendered the template so that we include the normal deletion response code in the output)
if self.resource.resp_status == 204:
self.resource.resp_status = 200
return template.render(context)
return ret
class JSONEmitter(BaseEmitter):
def emit(self, output):
......@@ -46,6 +51,7 @@ class XMLEmitter(BaseEmitter):
class HTMLEmitter(TemplatedEmitter):
template = 'emitter.html'
uses_forms = True
class TextEmitter(TemplatedEmitter):
template = 'emitter.txt'
......
{% load urlize_quoted_links %}<?xml version="1.0" encoding="UTF-8"?>
{% load urlize_quoted_links %}{% load add_query_param %}<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
......@@ -6,12 +6,19 @@
<style>
pre {border: 1px solid black; padding: 1em; background: #ffd}
div.action {padding: 0.5em 1em; margin-bottom: 0.5em; background: #ddf}
ul.accepttypes {float: right; list-style-type: none; margin: 0; padding: 0}
ul.accepttypes li {display: inline;}
form div {margin: 0.5em 0}
form div * {vertical-align: top}
form ul.errorlist {display: inline; margin: 0; padding: 0}
form ul.errorlist li {display: inline; color: red;}
.clearing {display: block; margin: 0; padding: 0; clear: both;}
</style>
<title>API - {{ resource.name }}</title>
</head>
<body>
<h1>{{ resource.name }}</h1>
<p>{{ resource.description }}</p>
<p>{{ resource.description|linebreaksbr }}</p>
<pre><b>{{ resource.resp_status }} {{ resource.resp_status_text }}</b>{% autoescape off %}
{% for key, val in resource.resp_headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
{% endfor %}
......@@ -20,14 +27,32 @@
{% if 'read' in resource.allowed_operations %}
<div class='action'>
<a href='{{ resource.request.path }}'>Read</a>
<ul class="accepttypes">
{% for content_type in resource.available_content_types %}
{% with resource.ACCEPT_PARAM|add:"="|add:content_type as param %}
<li>[<a href='{{ resource.request.path|add_query_param:param }}'>{{ content_type }}</a>]</li>
{% endwith %}
{% endfor %}
</ul>
<div class="clearing"></div>
</div>
{% endif %}
{% if 'create' in resource.allowed_operations %}
<div class='action'>
<form action="{{ resource.request.path }}" method="POST">
<form action="{{ resource.request.path }}" method="post">
{% csrf_token %}
{{ resource.form_instance.as_p }}
{% with resource.form_instance as form %}
{% for field in form %}
<div>
{{ field.label_tag }}:
{{ field }}
{{ field.help_text }}
{{ field.errors }}
</div>
{% endfor %}
{% endwith %}
<div class="clearing"></div>
<input type="submit" value="Create" />
</form>
</div>
......@@ -35,10 +60,20 @@
{% if 'update' in resource.allowed_operations %}
<div class='action'>
<form action="{{ resource.request.path }}" method="POST">
<form action="{{ resource.request.path }}" method="post">
<input type="hidden" name="{{ resource.METHOD_PARAM}}" value="PUT" />
{% csrf_token %}
{{ resource.form_instance.as_p }}
{% with resource.form_instance as form %}
{% for field in form %}
<div>
{{ field.label_tag }}:
{{ field }}
{{ field.help_text }}
{{ field.errors }}
</div>
{% endfor %}
{% endwith %}
<div class="clearing"></div>
<input type="submit" value="Update" />
</form>
</div>
......@@ -46,7 +81,7 @@
{% if 'delete' in resource.allowed_operations %}
<div class='action'>
<form action="{{ resource.request.path }}" method="POST">
<form action="{{ resource.request.path }}" method="post">
{% csrf_token %}
<input type="hidden" name="{{ resource.METHOD_PARAM}}" value="DELETE" />
<input type="submit" value="Delete" />
......
{{ resource.name }}
{{ resource.description }}
{% autoescape off %}HTTP/1.0 {{ resource.resp_status }} {{ resource.resp_status_text }}
......
from django.template import Library
from urlparse import urlparse, urlunparse
from urllib import quote
register = Library()
def add_query_param(url, param):
(key, val) = param.split('=')
param = '%s=%s' % (key, quote(val))
(scheme, netloc, path, params, query, fragment) = urlparse(url)
if query:
query += "&" + param
else:
query = param
return urlunparse((scheme, netloc, path, params, query, fragment))
register.filter('add_query_param', add_query_param)
......@@ -140,9 +140,9 @@ class XMLEmitter():
def _to_xml(self, xml, data):
if isinstance(data, (list, tuple)):
for item in data:
xml.startElement("resource", {})
xml.startElement("list-item", {})
self._to_xml(xml, item)
xml.endElement("resource")
xml.endElement("list-item")
elif isinstance(data, dict):
for key, value in data.iteritems():
......@@ -158,11 +158,11 @@ class XMLEmitter():
xml = SimplerXMLGenerator(stream, "utf-8")
xml.startDocument()
xml.startElement("content", {})
xml.startElement("root", {})
self._to_xml(xml, data)
xml.endElement("content")
xml.endElement("root")
xml.endDocument()
return stream.getvalue()
......
......@@ -40,8 +40,8 @@ RATING_CHOICES = ((0, 'Awful'),
class BlogPost(models.Model):
key = models.CharField(primary_key=True, max_length=64, default=uuid_str, editable=False)
title = models.CharField(max_length=128, help_text='The article title (Required)')
content = models.TextField(help_text='The article body (Required)')
title = models.CharField(max_length=128)
content = models.TextField()
created = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(editable=False, default='')
......@@ -74,11 +74,14 @@ class BlogPost(models.Model):
class Comment(models.Model):
blogpost = models.ForeignKey(BlogPost, editable=False, related_name='comments')
username = models.CharField(max_length=128, help_text='Please enter a username (Required)')
comment = models.TextField(help_text='Enter your comment here (Required)')
rating = models.IntegerField(blank=True, null=True, choices=RATING_CHOICES, help_text='Please rate the blog post (Optional)')
username = models.CharField(max_length=128)
comment = models.TextField()
rating = models.IntegerField(blank=True, null=True, choices=RATING_CHOICES, help_text='How did you rate this post?')
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('created',)
@models.permalink
def get_absolute_url(self):
return ('testapp.views.CommentInstance', (self.blogpost.key, self.id))
......@@ -86,5 +89,6 @@ class Comment(models.Model):
@property
@models.permalink
def blogpost_url(self):
"""Link to the blog post resource which this comment corresponds to."""
return ('testapp.views.BlogPostInstance', (self.blogpost.key,))
from rest.resource import Resource, ModelResource, QueryModelResource
from rest.resource import Resource
from rest.modelresource import ModelResource, QueryModelResource
from testapp.models import BlogPost, Comment
##### Root Resource #####
......
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