<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>fredrikholmstrom.com &#187; Django</title>
	<atom:link href="http://fredrikholmstrom.com/tag/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://fredrikholmstrom.com</link>
	<description>Java is to javascript what car is to carpet</description>
	<lastBuildDate>Sun, 16 Aug 2009 09:19:51 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.3</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Evolving Django&#8217;s Views</title>
		<link>http://fredrikholmstrom.com/evolving-djangos-views/</link>
		<comments>http://fredrikholmstrom.com/evolving-djangos-views/#comments</comments>
		<pubDate>Fri, 23 Jan 2009 15:12:09 +0000</pubDate>
		<dc:creator>Fredrik Holmström</dc:creator>
				<category><![CDATA[Everything]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://fredrikholmstrom.com/2009/01/30/</guid>
		<description><![CDATA[First of all: Last time I used Django was well over a year ago so if this is already possible to do with the current latest code base then shame on me, anyway &#8211; after messing around a bit with Django I got annoyed by the simplicity of the views, they&#8217;re very simple minded. I [...]]]></description>
			<content:encoded><![CDATA[<p>First of all: Last time I used Django was well over a year ago so if this is already possible to do with the current latest code base then shame on me, anyway &#8211; after messing around a bit with Django I got annoyed by the simplicity of the views, they&#8217;re very simple minded. I wanted some way of calling different functions depending on the request method and an easier way to return different output types, this is what I came up with.</p>
<p>The idea is simple, use a class with __call__ implemented instead of a function, within __call__ you can put custom logic to direct the requests to the appropriate callbacks &#8211; here&#8217;s my new base view class and a helper decorator (since Python 2.6 you can decorate classes).</p>
<pre class="prettyprint">
def view(cls):
	return cls()

class ClassView(object):

	fallback = "HTML"

	http_accept = {
		"application/xhtml\+xml": "HTML",
		"text/html":"HTML",
		"application/json": "JSON",
		"text/javascript": "JSON",
		"application/xml": "XML"
	}

	request_method = {
		"GET": "READ",
		"POST": "WRITE",
		"PUT": "WRITE",
		"DELETE": "WRITE"
	}

	def __call__(self, request):
		accept = request.META["HTTP_ACCEPT"]
		method = getattr(self, self.request_method[request.META["REQUEST_METHOD"]])

		for regex, call in self.http_accept.items():
			if regex and re.search(regex, accept):
				return getattr(self, call)(request, method(request))

		return getattr(self, self.fallback)(request, method(request))

	def READ(self, request):
		pass

	def WRITE(self, request):
		pass

	def JSON(self, request, method_vars):
		pass

	def HTML(self, request, method_vars):
		pass

	def XML(self, request, method_vars):
		pass
</pre>
<p>Now when I want to create a new view in django, instead of doing something like this:</p>
<pre class="prettyprint">
def index(request):
     # blah
</pre>
<p>I do this:</p>
<pre class="prettyprint">
# for python < 2.6 remove/comment out this next line:
@view
class index(ClassView):

	def READ(self, request):
		return {"title": "Hello World!"}

	def HTML(self, request, method_vars):
		return render_to_response("frontend/index.html", method_vars)

	def JSON(self, request, method_vars):
		return HttpResponse('{"title":"%(title)s"}' % method_vars)

# for python < 2.6 uncomment the next line
# index = view(index)
</pre>
<p>The READ method will be called on all GET requests, while the WRITE method will be called on all POST, PUT and DELETE. After which the appropriate output method will be selected based on the HTTP Accept header. This allows me to group common functionality in READ for all GET requests to one URL and then still be allowed to do output specific (HTML, XML, JSON, etc.) logic and template rendering based on what content types the client accepts (for example I will probably need to load more objects for HTML output since it usually has a rather advanced layout compared to say JSON which probably only wants to return the object collection as JSON string)</p>
]]></content:encoded>
			<wfw:commentRss>http://fredrikholmstrom.com/evolving-djangos-views/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
