Commit b0ce3f92 by Tom Christie

Added formats, various form improvements, more refactoring/cleanup

parent 764fbe33
...@@ -3,6 +3,8 @@ import json ...@@ -3,6 +3,8 @@ import json
from utils import dict2xml from utils import dict2xml
class BaseEmitter(object): class BaseEmitter(object):
uses_forms = False
def __init__(self, resource): def __init__(self, resource):
self.resource = resource self.resource = resource
...@@ -24,11 +26,14 @@ class TemplatedEmitter(BaseEmitter): ...@@ -24,11 +26,14 @@ class TemplatedEmitter(BaseEmitter):
'resource': self.resource, 'resource': self.resource,
}) })
ret = template.render(context)
# Munge DELETE Response code to allow us to return content # 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: if self.resource.resp_status == 204:
self.resource.resp_status = 200 self.resource.resp_status = 200
return template.render(context) return ret
class JSONEmitter(BaseEmitter): class JSONEmitter(BaseEmitter):
def emit(self, output): def emit(self, output):
...@@ -46,6 +51,7 @@ class XMLEmitter(BaseEmitter): ...@@ -46,6 +51,7 @@ class XMLEmitter(BaseEmitter):
class HTMLEmitter(TemplatedEmitter): class HTMLEmitter(TemplatedEmitter):
template = 'emitter.html' template = 'emitter.html'
uses_forms = True
class TextEmitter(TemplatedEmitter): class TextEmitter(TemplatedEmitter):
template = 'emitter.txt' 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" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
...@@ -6,12 +6,19 @@ ...@@ -6,12 +6,19 @@
<style> <style>
pre {border: 1px solid black; padding: 1em; background: #ffd} pre {border: 1px solid black; padding: 1em; background: #ffd}
div.action {padding: 0.5em 1em; margin-bottom: 0.5em; background: #ddf} 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> </style>
<title>API - {{ resource.name }}</title> <title>API - {{ resource.name }}</title>
</head> </head>
<body> <body>
<h1>{{ resource.name }}</h1> <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 %} <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 }} {% for key, val in resource.resp_headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
{% endfor %} {% endfor %}
...@@ -20,14 +27,32 @@ ...@@ -20,14 +27,32 @@
{% if 'read' in resource.allowed_operations %} {% if 'read' in resource.allowed_operations %}
<div class='action'> <div class='action'>
<a href='{{ resource.request.path }}'>Read</a> <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> </div>
{% endif %} {% endif %}
{% if 'create' in resource.allowed_operations %} {% if 'create' in resource.allowed_operations %}
<div class='action'> <div class='action'>
<form action="{{ resource.request.path }}" method="POST"> <form action="{{ resource.request.path }}" method="post">
{% csrf_token %} {% 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" /> <input type="submit" value="Create" />
</form> </form>
</div> </div>
...@@ -35,10 +60,20 @@ ...@@ -35,10 +60,20 @@
{% if 'update' in resource.allowed_operations %} {% if 'update' in resource.allowed_operations %}
<div class='action'> <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" /> <input type="hidden" name="{{ resource.METHOD_PARAM}}" value="PUT" />
{% csrf_token %} {% 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" /> <input type="submit" value="Update" />
</form> </form>
</div> </div>
...@@ -46,7 +81,7 @@ ...@@ -46,7 +81,7 @@
{% if 'delete' in resource.allowed_operations %} {% if 'delete' in resource.allowed_operations %}
<div class='action'> <div class='action'>
<form action="{{ resource.request.path }}" method="POST"> <form action="{{ resource.request.path }}" method="post">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="{{ resource.METHOD_PARAM}}" value="DELETE" /> <input type="hidden" name="{{ resource.METHOD_PARAM}}" value="DELETE" />
<input type="submit" value="Delete" /> <input type="submit" value="Delete" />
......
{{ resource.name }} {{ resource.name }}
{{ resource.description }} {{ resource.description }}
{% autoescape off %}HTTP/1.0 {{ resource.resp_status }} {{ resource.resp_status_text }} {% 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(): ...@@ -140,9 +140,9 @@ class XMLEmitter():
def _to_xml(self, xml, data): def _to_xml(self, xml, data):
if isinstance(data, (list, tuple)): if isinstance(data, (list, tuple)):
for item in data: for item in data:
xml.startElement("resource", {}) xml.startElement("list-item", {})
self._to_xml(xml, item) self._to_xml(xml, item)
xml.endElement("resource") xml.endElement("list-item")
elif isinstance(data, dict): elif isinstance(data, dict):
for key, value in data.iteritems(): for key, value in data.iteritems():
...@@ -158,11 +158,11 @@ class XMLEmitter(): ...@@ -158,11 +158,11 @@ class XMLEmitter():
xml = SimplerXMLGenerator(stream, "utf-8") xml = SimplerXMLGenerator(stream, "utf-8")
xml.startDocument() xml.startDocument()
xml.startElement("content", {}) xml.startElement("root", {})
self._to_xml(xml, data) self._to_xml(xml, data)
xml.endElement("content") xml.endElement("root")
xml.endDocument() xml.endDocument()
return stream.getvalue() return stream.getvalue()
......
...@@ -40,8 +40,8 @@ RATING_CHOICES = ((0, 'Awful'), ...@@ -40,8 +40,8 @@ RATING_CHOICES = ((0, 'Awful'),
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, help_text='The article title (Required)') title = models.CharField(max_length=128)
content = models.TextField(help_text='The article body (Required)') content = models.TextField()
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(editable=False, default='') slug = models.SlugField(editable=False, default='')
...@@ -74,11 +74,14 @@ class BlogPost(models.Model): ...@@ -74,11 +74,14 @@ class BlogPost(models.Model):
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, help_text='Please enter a username (Required)') username = models.CharField(max_length=128)
comment = models.TextField(help_text='Enter your comment here (Required)') comment = models.TextField()
rating = models.IntegerField(blank=True, null=True, choices=RATING_CHOICES, help_text='Please rate the blog post (Optional)') 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) created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('created',)
@models.permalink @models.permalink
def get_absolute_url(self): def get_absolute_url(self):
return ('testapp.views.CommentInstance', (self.blogpost.key, self.id)) return ('testapp.views.CommentInstance', (self.blogpost.key, self.id))
...@@ -86,5 +89,6 @@ class Comment(models.Model): ...@@ -86,5 +89,6 @@ class Comment(models.Model):
@property @property
@models.permalink @models.permalink
def blogpost_url(self): def blogpost_url(self):
"""Link to the blog post resource which this comment corresponds to."""
return ('testapp.views.BlogPostInstance', (self.blogpost.key,)) 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 from testapp.models import BlogPost, Comment
##### Root Resource ##### ##### 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