<?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>muhuk.com &#187; template</title>
	<atom:link href="http://www.muhuk.com/tag/template/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.muhuk.com</link>
	<description>know thyself</description>
	<lastBuildDate>Thu, 29 Dec 2011 05:05:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>A Civilized Way Display Lots Of Data</title>
		<link>http://www.muhuk.com/2009/08/a-civilized-way-display-lots-of-data/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=a-civilized-way-display-lots-of-data</link>
		<comments>http://www.muhuk.com/2009/08/a-civilized-way-display-lots-of-data/#comments</comments>
		<pubDate>Mon, 31 Aug 2009 08:05:18 +0000</pubDate>
		<dc:creator>Atamert Ölçgen</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[pagination]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[template]]></category>

		<guid isPermaLink="false">http://www.muhuk.com/?p=274</guid>
		<description><![CDATA[Django is a civilized way to build web applications. Pagination is a civilized way to display lots of data. There are still people developing websites with tens of thousands of items crammed in a single page. Even if you use JavaScript to paginate client-side, never ending download results in poor user experience. Django has pagination [...]<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://www.muhuk.com/2009/08/a-civilized-way-display-lots-of-data/' addthis:title='A Civilized Way Display Lots Of Data '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.djangoproject.com">Django</a> is a civilized way to build web applications. Pagination is a civilized way to display lots of data. There are still people developing websites with tens of thousands of items crammed in a single page. Even if you use JavaScript to paginate client-side, never ending download results in poor user experience.</p>

<p>Django has <a href="http://docs.djangoproject.com/en/dev/topics/pagination/">pagination</a> support built-in. All you need to do is to wrap your <code>QuerySet</code> with <code>django.core.paginator.Paginator</code> and add <code>paginator.page(some_page_number)</code> to your template context. Then you can use attributes/methods such as <code>has_next</code> and <code>num_pages</code> or iterate over <code>page_range</code> to display your pagination navigation. To access items in current page you can use <code>object_list</code>, which is in fact a <code>QuerySet</code> sliced with correct limits. That also means; only those items that you want to display are queried. It&#8217;s all <a href="http://docs.djangoproject.com/en/dev/topics/pagination/">documented well</a> as usual.</p>

<h3>Django-pagination Takes It One Step Further</h3>

<p>In my opinion pagination belongs to presentation. If you have many queries/views to paginate, you might find yourself repetitively writing pagination code. You can move all your pagination code into the template with <a href="http://code.google.com/p/django-pagination/">django-pagination</a>. This is accomplished with a middleware and a set of template tags.</p>

<p>With django-pagination you can paginate your results like this:</p>

<pre><code>{% autopaginate object_list %}

{% for object in object_list %}
  {{ object }}
{% endfor %}

{% paginate %}
</code></pre>

<p><code>autopaginate</code> tag replaces your <code>QuerySet</code> with a paginator and <code>paginate</code> tag renders <code>pagination/pagination.html</code> template with correct values.</p>

<p>You can download django-pagination from <a href="http://code.google.com/p/django-pagination/downloads/list">Google Code</a>, but appereantly development is moved to <a href="http://github.com/ericflo/django-pagination/tree/master">GitHub</a>. I wish there was a message left on the Google Code page.</p>

<h3>A Little SEO Shouldn&#8217;t Hurt</h3>

<p>When you have a paginated view, you usually display the results of the first page if the pagination variable is missing. As a result <code>/some_view/</code> and <code>/some_view/?page=1</code> return identical responses. This might be interpreted by search engines as a duplicate. My solution for this is to redirect the first page to the page without a page variable:</p>

<pre><span style="color:#555555">   1 </span><span style="color:#000000; font-weight:bold">from</span> django<span style="color:#000000">.</span>http <span style="color:#000000; font-weight:bold">import</span> HttpResponsePermanentRedirect
<span style="color:#555555">   2 </span><span style="color:#000000; font-weight:bold">from</span> pagination<span style="color:#000000">.</span>middleware <span style="color:#000000; font-weight:bold">import</span> PaginationMiddleware
<span style="color:#555555">   3 </span>
<span style="color:#555555">   4 </span><span style="color:#000000; font-weight:bold">class</span> <span style="color:#010181">SEOPaginationMiddleware</span><span style="color:#000000">(</span>PaginationMiddleware<span style="color:#000000">):</span>
<span style="color:#555555">   5 </span>    <span style="color:#000000; font-weight:bold">def</span> <span style="color:#010181">process_request</span><span style="color:#000000">(</span>self<span style="color:#000000">,</span> request<span style="color:#000000">):</span>
<span style="color:#555555">   6 </span>        <span style="color:#000000; font-weight:bold">if</span> request<span style="color:#000000">.</span>method <span style="color:#000000">==</span> <span style="color:#ff0000">'GET'</span><span style="color:#000000">:</span>
<span style="color:#555555">   7 </span>            <span style="color:#000000; font-weight:bold">try</span><span style="color:#000000">:</span>
<span style="color:#555555">   8 </span>                page <span style="color:#000000">=</span> <span style="color:#830000">int</span><span style="color:#000000">(</span>request<span style="color:#000000">.</span>GET<span style="color:#000000">[</span><span style="color:#ff0000">'page'</span><span style="color:#000000">])</span>
<span style="color:#555555">   9 </span>            <span style="color:#000000; font-weight:bold">except</span> <span style="color:#000000">(</span><span style="color:#000000; font-weight:bold">KeyError</span><span style="color:#000000">,</span> <span style="color:#000000; font-weight:bold">ValueError</span><span style="color:#000000">,</span> <span style="color:#000000; font-weight:bold">TypeError</span><span style="color:#000000">):</span>
<span style="color:#555555">  10 </span>                page <span style="color:#000000">=</span> <span style="color:#000000; font-weight:bold">None</span>
<span style="color:#555555">  11 </span>            <span style="color:#000000; font-weight:bold">if</span> page <span style="color:#000000">==</span> <span style="color:#2928ff">1</span><span style="color:#000000">:</span>
<span style="color:#555555">  12 </span>                params <span style="color:#000000">=</span> request<span style="color:#000000">.</span>GET<span style="color:#000000">.</span><span style="color:#010181">copy</span><span style="color:#000000">()</span>
<span style="color:#555555">  13 </span>                <span style="color:#000000; font-weight:bold">del</span><span style="color:#000000">(</span>params<span style="color:#000000">[</span><span style="color:#ff0000">'page'</span><span style="color:#000000">])</span>
<span style="color:#555555">  14 </span>                path <span style="color:#000000">=</span> request<span style="color:#000000">.</span>path
<span style="color:#555555">  15 </span>                <span style="color:#000000; font-weight:bold">if</span> params<span style="color:#000000">:</span>
<span style="color:#555555">  16 </span>                    path <span style="color:#000000">+=</span> <span style="color:#ff0000">'?'</span> <span style="color:#000000">+</span> params<span style="color:#000000">.</span><span style="color:#010181">urlencode</span><span style="color:#000000">()</span>
<span style="color:#555555">  17 </span>                <span style="color:#000000; font-weight:bold">return</span> <span style="color:#010181">HttpResponsePermanentRedirect</span><span style="color:#000000">(</span>path<span style="color:#000000">)</span>
<span style="color:#555555">  18 </span>        <span style="color:#000000; font-weight:bold">return</span> <span style="color:#830000">super</span><span style="color:#000000">(</span>SEOPaginationMiddleware<span style="color:#000000">,</span> self<span style="color:#000000">).</span><span style="color:#010181">process_request</span><span style="color:#000000">(</span>request<span style="color:#000000">)</span>
</pre>

<p>This works only if your page variable is an URL parameter (i.e. you are using <code>GET</code>).</p>
<div><a class="addthis_button" href="http://www.muhuk.com//addthis.com/bookmark.php?v=250" addthis:url='http://www.muhuk.com/2009/08/a-civilized-way-display-lots-of-data/' addthis:title='A Civilized Way Display Lots Of Data '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div><p>Related posts:<ol>
<li><a href='http://www.muhuk.com/2011/06/pycon-apac-optimizing-media-performance-with-django_compressor/' rel='bookmark' title='My PyCon APAC 2011 Presentation: Optimizing Media Performance with django_compressor'>My PyCon APAC 2011 Presentation: Optimizing Media Performance with django_compressor</a></li>
<li><a href='http://www.muhuk.com/2011/11/working-with-files-in-django/' rel='bookmark' title='Working with files in Django &#8211; Part 1'>Working with files in Django &#8211; Part 1</a></li>
<li><a href='http://www.muhuk.com/2011/11/working-with-files-in-django-part-2/' rel='bookmark' title='Working with files in Django &#8211; Part 2'>Working with files in Django &#8211; Part 2</a></li>
</ol></p> <p><a href="http://www.muhuk.com/?flattrss_redirect&amp;id=274&amp;md5=d450f8a4bf70ac173e1a33fc4eed4e70" title="Flattr" target="_blank"><img src="http://www.muhuk.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.muhuk.com/2009/08/a-civilized-way-display-lots-of-data/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<atom:link rel="payment" href="http://www.muhuk.com/?flattrss_redirect&amp;id=274&amp;md5=d450f8a4bf70ac173e1a33fc4eed4e70" type="text/html" />
	</item>
		<item>
		<title>Serving Static Media In Django Development Server</title>
		<link>http://www.muhuk.com/2009/05/serving-static-media-in-django-development-server/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=serving-static-media-in-django-development-server</link>
		<comments>http://www.muhuk.com/2009/05/serving-static-media-in-django-development-server/#comments</comments>
		<pubDate>Mon, 25 May 2009 09:30:10 +0000</pubDate>
		<dc:creator>Atamert Ölçgen</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[media]]></category>
		<category><![CDATA[template]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.muhuk.com/?p=225</guid>
		<description><![CDATA[There is a newer version of this post. Information below is no longer valid! There is a misconception about how static files (a.k.a media files) are handled in Django. Actually it is quite clearly documented here and here. Nevertheless a question about this comes up in the mailing-list or IRC channel frequently: Where do I [...]<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://www.muhuk.com/2009/05/serving-static-media-in-django-development-server/' addthis:title='Serving Static Media In Django Development Server '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div>]]></description>
			<content:encoded><![CDATA[<hr />

<p><b>There is a <a href="http://www.muhuk.com/2011/11/working-with-files-in-django/">newer version of this post</a>. Information below is no longer valid!</b></p>

<hr />

<p>There is a misconception about how static files (a.k.a media files) are handled in Django. Actually it is quite clearly documented <a href="http://docs.djangoproject.com/en/dev/howto/static-files/#module-django.views.static">here</a> and <a href="http://docs.djangoproject.com/en/dev/howto/deployment/modpython/#id1">here</a>. Nevertheless a question about this comes up in the mailing-list or IRC channel frequently:</p>

<blockquote>
  <p>Where do I put my media files?</p>
  
  <p>Django can&#8217;t find my <code>foo.gif</code>!</p>
  
  <p>How can I link my CSS?</p>
</blockquote>

<p>First of all, just to make it clear; <strong>just because a server returns a response body with an internal URL doesn&#8217;t necessarily mean it will be available on that server</strong>. It is one thing that your templates produce the correct URL to a media file and another thing that your server actually serves that resource on that URL. <strong>Django development server doesn&#8217;t automagically serve media files</strong><sup>1</sup>.</p>

<h3>Settings</h3>

<p>There are three settings to get right: <code>MEDIA_ROOT</code>, <code>MEDIA_URL</code> and <code>ADMIN_MEDIA_PREFIX</code>. <code>MEDIA_ROOT</code> is the <em>absolute filesystem path</em> where your media files are. I usually set it like:</p>

<pre><code>MEDIA_ROOT = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'media')
</code></pre>

<p>This will set <code>MEDIA_ROOT</code> to point to the <code>media</code> directory in your project directory<sup>2</sup>. <code>MEDIA_URL</code> and <code>ADMIN_MEDIA_PREFIX</code> are <em>URL&#8217;s</em>:</p>

<pre><code>MEDIA_URL = '/media/'
ADMIN_MEDIA_PREFIX = '/media/admin/'
</code></pre>

<p>With this setup, to serve admin media in production, all I need to do is to symlink media folder of admin app into my media directory. Of course you can set <code>MEDIA_URL</code> to point to another domain/subdomain. Such as <code>http://media.mydomain.com/</code>. But this way you can&#8217;t serve your media from development server.</p>

<h3>URL Configuration</h3>

<p>Add the following code snipplet at the end of your root <code>urls.py</code>:</p>

<pre><span style="color:#555555">   1 </span><span style="color:#000000; font-weight:bold">if</span> settings<span style="color:#000000">.</span>DEBUG<span style="color:#000000">:</span>
<span style="color:#555555">   2 </span>    <span style="color:#000000; font-weight:bold">from</span> django<span style="color:#000000">.</span>views<span style="color:#000000">.</span>static <span style="color:#000000; font-weight:bold">import</span> serve
<span style="color:#555555">   3 </span>    _media_url <span style="color:#000000">=</span> settings<span style="color:#000000">.</span>MEDIA_URL
<span style="color:#555555">   4 </span>    <span style="color:#000000; font-weight:bold">if</span> _media_url<span style="color:#000000">.</span><span style="color:#010181">startswith</span><span style="color:#000000">(</span><span style="color:#ff0000">'/'</span><span style="color:#000000">):</span>
<span style="color:#555555">   5 </span>        _media_url <span style="color:#000000">=</span> _media_url<span style="color:#000000">[</span><span style="color:#2928ff">1</span><span style="color:#000000">:]</span>
<span style="color:#555555">   6 </span>        urlpatterns <span style="color:#000000">+=</span> <span style="color:#010181">patterns</span><span style="color:#000000">(</span><span style="color:#ff0000">''</span><span style="color:#000000">,</span>
<span style="color:#555555">   7 </span>                                <span style="color:#000000">(</span>r<span style="color:#ff0000">'^%s(?P&lt;path&gt;.*)$'</span> <span style="color:#000000">%</span> _media_url<span style="color:#000000">,</span>
<span style="color:#555555">   8 </span>                                serve<span style="color:#000000">,</span>
<span style="color:#555555">   9 </span>                                <span style="color:#000000">{</span><span style="color:#ff0000">'document_root'</span><span style="color:#000000">:</span> settings<span style="color:#000000">.</span>MEDIA_ROOT<span style="color:#000000">}))</span>
<span style="color:#555555">  10 </span>    <span style="color:#000000; font-weight:bold">del</span><span style="color:#000000">(</span>_media_url<span style="color:#000000">,</span> serve<span style="color:#000000">)</span>
</pre>

<p><code>settings.DEBUG == True</code> doesn&#8217;t necessarily mean development server is running. But it is a good indicator since deploying with development server is not a good idea for many reasons. Notice here we don&#8217;t serve media unless <code>MEDIA_URL</code> is an absolute URL on our server.</p>

<h3>Templates</h3>

<p>Finally we need to specify media URL&#8217;s correctly. To avoid hard-coding media path we will be using <code>{{ MEDIA_URL }}</code> context variable in our templates. To have <code>{{ MEDIA_URL }}</code> included automatically in each template we need to do two things:</p>

<ol>
<li>Make sure you have <code>django.core.context_processors.media</code> in your <code>TEMPLATE_CONTEXT_PROCESSORS</code>.</li>
<li>Make sure each view is using a <a href="http://docs.djangoproject.com/en/dev/ref/templates/api/#id1"><code>RequestContext</code></a>.</li>
</ol>

<p>Afterwards all we need to do is to specify our media URL&#8217;s like this:</p>

<pre><code>&lt;img src="<b>{{ MEDIA_URL }}</b>img/header.jpeg" /&gt;</code></pre>

<p>This will be translated to:</p>

<pre><code>&lt;img src="/media/img/header.jpeg" /&gt;
</code></pre>

<h3>Bonus</h3>

<p>While we are at it, why not serve our <code>500</code> and <code>404</code> pages statically. When <code>DEBUG == True</code>, 500 (server error) and 404 (not found) situations are handled with special debugging views. So there&#8217;s no chance to test your error pages. Add the following code, just like static serving code:</p>

<pre><span style="color:#555555">   1 </span><span style="color:#000000; font-weight:bold">if</span> settings<span style="color:#000000">.</span>DEBUG<span style="color:#000000">:</span>
<span style="color:#555555">   2 </span>    urlpatterns <span style="color:#000000">+=</span> <span style="color:#010181">patterns</span><span style="color:#000000">(</span><span style="color:#ff0000">''</span><span style="color:#000000">,</span>
<span style="color:#555555">   3 </span>                            <span style="color:#000000">(</span>r<span style="color:#ff0000">'^404/'</span><span style="color:#000000">,</span>
<span style="color:#555555">   4 </span>                                <span style="color:#ff0000">'django.views.generic.simple.'</span> \
<span style="color:#555555">   5 </span>                                <span style="color:#ff0000">'direct_to_template'</span><span style="color:#000000">,</span>
<span style="color:#555555">   6 </span>                                <span style="color:#000000">{</span><span style="color:#ff0000">'template'</span><span style="color:#000000">:</span> <span style="color:#ff0000">'404.html'</span><span style="color:#000000">}),</span>
<span style="color:#555555">   7 </span>                            <span style="color:#000000">(</span>r<span style="color:#ff0000">'^500/'</span><span style="color:#000000">,</span>
<span style="color:#555555">   8 </span>                                <span style="color:#ff0000">'django.views.generic.simple.'</span> \
<span style="color:#555555">   9 </span>                                <span style="color:#ff0000">'direct_to_template'</span><span style="color:#000000">,</span>
<span style="color:#555555">  10 </span>                                <span style="color:#000000">{</span><span style="color:#ff0000">'template'</span><span style="color:#000000">:</span> <span style="color:#ff0000">'500.html'</span><span style="color:#000000">}))</span>
</pre>

<p>Now when you visit <code>/500/</code> and <code>/404/</code> on your development server you will be served a fake error page.</p>

<hr />

<p><strong>1</strong>: There is an exception here. If you configured your settings correctly, development server will serve admin media.</p>

<p><strong>2</strong>: Assuming your <code>settings.py</code> is directly inside your project directory, hence the <code>__file__</code>.</p>
<div><a class="addthis_button" href="http://www.muhuk.com//addthis.com/bookmark.php?v=250" addthis:url='http://www.muhuk.com/2009/05/serving-static-media-in-django-development-server/' addthis:title='Serving Static Media In Django Development Server '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div><p>Related posts:<ol>
<li><a href='http://www.muhuk.com/2011/06/pycon-apac-optimizing-media-performance-with-django_compressor/' rel='bookmark' title='My PyCon APAC 2011 Presentation: Optimizing Media Performance with django_compressor'>My PyCon APAC 2011 Presentation: Optimizing Media Performance with django_compressor</a></li>
<li><a href='http://www.muhuk.com/2011/11/working-with-files-in-django/' rel='bookmark' title='Working with files in Django &#8211; Part 1'>Working with files in Django &#8211; Part 1</a></li>
<li><a href='http://www.muhuk.com/2011/11/working-with-files-in-django-part-2/' rel='bookmark' title='Working with files in Django &#8211; Part 2'>Working with files in Django &#8211; Part 2</a></li>
</ol></p> <p><a href="http://www.muhuk.com/?flattrss_redirect&amp;id=225&amp;md5=01b286ad479134b6a9641d941a3c5f07" title="Flattr" target="_blank"><img src="http://www.muhuk.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.muhuk.com/2009/05/serving-static-media-in-django-development-server/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<atom:link rel="payment" href="http://www.muhuk.com/?flattrss_redirect&amp;id=225&amp;md5=01b286ad479134b6a9641d941a3c5f07" type="text/html" />
	</item>
		<item>
		<title>Does Django Need An Overhaul?</title>
		<link>http://www.muhuk.com/2008/09/does-django-need-an-overhaul/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=does-django-need-an-overhaul</link>
		<comments>http://www.muhuk.com/2008/09/does-django-need-an-overhaul/#comments</comments>
		<pubDate>Fri, 26 Sep 2008 19:04:57 +0000</pubDate>
		<dc:creator>Atamert Ölçgen</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[jinja]]></category>
		<category><![CDATA[template]]></category>

		<guid isPermaLink="false">http://www.muhuk.com/?p=19</guid>
		<description><![CDATA[When I wrote Freedom is Power, I was pissed off because of the extra work of extracting all the info into the context for Django&#8217;s templating system doesn&#8217;t support enough logic. You have to create many little variables to be inserted only once in the template, while you could have just passed the model instance [...]<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://www.muhuk.com/2008/09/does-django-need-an-overhaul/' addthis:title='Does Django Need An Overhaul? '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div>]]></description>
			<content:encoded><![CDATA[<p>When I wrote <a href="http://www.muhuk.com/2008/07/freedom-is-power/">Freedom is Power</a>, I was pissed off because of the extra work of extracting all the info into the context for Django&#8217;s templating system doesn&#8217;t support enough logic. You have to create many little variables to be inserted only once in the template, while you could have just passed the model instance itself. Coding and maintenance becomes harder.</p>

<p>I have done some thinking over this but I am still not sure. If you&#8217;re doing both the views and templates yourself then it can be overkill. Just like static typing, or public/private/protected discrimination. On the other hand for design-heavy projects, where there is a seperate template designer who doesn&#8217;t know/care much about programming it makes sense. Still the possibility of having adequate presentation logic in templates is a good thing. It shouldn&#8217;t hurt anyone.</p>

<p>Last week (jinja dev) Armin Ronacher has posted an article named &#8220;<a href="http://lucumr.pocoo.org/cogitations/2008/09/16/why-jinja-is-not-django-and-why-django-should-have-a-look-at-it/">Why Jinja is not Django and why Django should have a look at it</a>&#8220;. It is a comprehensive comparison of internal workings of both templating engines. Inevitably it is a little biased, but I think each argument is valid and important. If you are into Django, it is a good read. There is also some speed comparison to back it up.</p>

<p>I am currently working on a project using Django. But I don&#8217;t touch the templating engine for this one. Everything served as JSON. <img src='http://www.muhuk.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<div><a class="addthis_button" href="http://www.muhuk.com//addthis.com/bookmark.php?v=250" addthis:url='http://www.muhuk.com/2008/09/does-django-need-an-overhaul/' addthis:title='Does Django Need An Overhaul? '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div><p>Related posts:<ol>
<li><a href='http://www.muhuk.com/2011/11/working-with-files-in-django/' rel='bookmark' title='Working with files in Django &#8211; Part 1'>Working with files in Django &#8211; Part 1</a></li>
<li><a href='http://www.muhuk.com/2011/11/working-with-files-in-django-part-2/' rel='bookmark' title='Working with files in Django &#8211; Part 2'>Working with files in Django &#8211; Part 2</a></li>
<li><a href='http://www.muhuk.com/2011/11/working-with-files-in-django-part-3/' rel='bookmark' title='Working with files in Django &#8211; Part 3'>Working with files in Django &#8211; Part 3</a></li>
</ol></p> <p><a href="http://www.muhuk.com/?flattrss_redirect&amp;id=19&amp;md5=a8481ca2b7588c66c6474aac45f4b2c6" title="Flattr" target="_blank"><img src="http://www.muhuk.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.muhuk.com/2008/09/does-django-need-an-overhaul/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="http://www.muhuk.com/?flattrss_redirect&amp;id=19&amp;md5=a8481ca2b7588c66c6474aac45f4b2c6" type="text/html" />
	</item>
		<item>
		<title>Freedom is Power</title>
		<link>http://www.muhuk.com/2008/07/freedom-is-power/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=freedom-is-power</link>
		<comments>http://www.muhuk.com/2008/07/freedom-is-power/#comments</comments>
		<pubDate>Mon, 14 Jul 2008 20:02:05 +0000</pubDate>
		<dc:creator>Atamert Ölçgen</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[jinja]]></category>
		<category><![CDATA[template]]></category>

		<guid isPermaLink="false">http://www.muhuk.com/?p=5</guid>
		<description><![CDATA[If one sticks too rigidly to one&#8217;s principles, one would hardly see anybody. (Agatha Christie) Web applications are thin client (your browser) applications you access through an intranet or the Internet. Due to initial design of WWW, to create rich applications you need to deal with quite a large number of protocols/languages/concepts. To name a [...]<div><a class="addthis_button" href="//addthis.com/bookmark.php?v=250" addthis:url='http://www.muhuk.com/2008/07/freedom-is-power/' addthis:title='Freedom is Power '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div>]]></description>
			<content:encoded><![CDATA[<blockquote>
  <p>If one sticks too rigidly to one&#8217;s principles, one would hardly see anybody. (Agatha Christie)</p>
</blockquote>

<p>Web applications are thin client (your browser) applications you access through an intranet or the Internet. Due to initial design of WWW, to create rich applications you need to deal with quite a large number of protocols/languages/concepts. To name a few; you need to know about JavaScript, CSS, HTML (preferably XHTML) and (possibly) JSON to write an AJAX application. This is only client side, the front end.</p>

<p>To preserve sanity, a layered approach that divides and isolates different parts of the application as much as possible is usually preferred. MVC pattern, which stands for Model-View-Controller, is a popular method for layering. Model is the layer where your data storage and manipulation occur. View is the layer where the presentation of model occur. The controller layer is basically the glue between both, where your so-called <a href="http://en.wikipedia.org/wiki/Business_rules">business rules</a> should be. MVC pattern allows us to change the user interaction or to adapt different back ends with minimal modifications.[1]</p>

<p>I would like to summarize how a web application using MVC pattern works. But before that I need to state that this is an overly simplified model I will present.</p>

<ol>
<li>When an HTTP request comes to our server a <code>request</code> object is created. This <code>request</code> object might have come modified according to our configuration before we have access to it. For example we might have wanted our request body to be decoded to unicode.</li>
<li>The <code>request</code> object is passed to a <code>view</code> function, depending on our configuration again. URL patterns might be matched against view functions or, rarely, against HTTP method (GET, POST, etc) or an entirely different method can be used to determine which view function to call.</li>
<li>The <code>view</code> function communicates with the <code>model</code>, adds, deletes or modifies the models as needed. Or it might just pull some data out and present it to user.</li>
<li>We can generate the <code>response</code> from our <code>view</code> but, it is preferred to use another template layer. Because that way you can seperate application logic and presentation logic. In that case the <code>view</code> function returns the necessary information into a <code>template</code> object.</li>
<li>The <code>template</code> object receives the data from the <code>view</code> and renders the final response (an HTML page, an XML document, etc).</li>
</ol>

<p>We can pass data from <code>view</code> to <code>template</code> in a number of ways. We can use dictionaries (hashmaps) with arbitrary objects as values for example. When we return this dictionary from our <code>view</code> function the <code>template</code> objects picks it up and makes the data available by reference to its keys.</p>

<p>What we pass depends on the presentation logic in the <code>template</code>. Just to give you an idea, say we have a query page, where the user simply asks for a particular piece of data and we present it;</p>

<ul>
<li>It will surely need a reference to that data. (Maybe a model instance if you are using an <a href="http://en.wikipedia.org/wiki/Object-relational_mapping">ORM</a>)</li>
<li>It may present data conditionally, some parts might be available only to the administrators and invisible to normal users for example. So we would need to pass <em>something</em> to determine these conditions. I&#8217;ll come back to that <em>something</em> later.</li>
<li>It may have other elements (on the page) that need references to other data. (There might me a dynamically generated menu on certain pages for instance)</li>
</ul>

<p>This means we would pass three kinds of references to a template; primary data, conditinal information and secondary data. I have mentioned that when we have templates we can seperate application logic (business rules?) and presentation logic. In (beautiful) web framework <a href="http://www.djangoproject.com/">Django</a>&#8216;s documentation it is said;</p>

<blockquote>
  <p>&#8230;the template system is meant to express presentation, not program logic.</p>
</blockquote>

<p>and</p>

<blockquote>
  <p>We see a template system as a tool that controls presentation and presentation-related logic — and that’s it. The template system shouldn’t support functionality that goes beyond this basic goal.</p>
  
  <p>If we wanted to put everything in templates, we’d be using PHP. Been there, done that, wised up.</p>
</blockquote>

<p>I read <em>presentation</em> as laying out output and <em>program logic</em> as inserting/querying/modifying/deleting. This takes us back to the <em>something</em> I would like to discuss. How do we pass information related to conditional rendering. What we pass depends greatly on the functionality of the template engine. Let me illustrate with an example;</p>

<blockquote>
  <p>We want to display a tip if;</p>
  
  <ul>
  <li>A user who is registered for at least 2 weeks ago.</li>
  <li>Who has less than 5 friends.</li>
  <li>No other warning, such as a form validation error, is present on the page.</li>
  </ul>
</blockquote>

<p>My intuition tells me I would need a reference to the list of errors and the (authenticated) user object in my template. I would like to have a reference to my user object because if I get anything less I might have to modify the <code>view</code> if the requirements change. So the registration date with the friend count would not do. After all we are deciding whether or not to show a tip, we are not doing inserting/querying/modifying/deleting I mentioned earlier.</p>

<p>Suppose we have <code>user</code> and <code>error</code> passed into our template, how do we use them; [2]</p>

<pre><code>{% if user.registered.today().toordinal()
    -user.registered.toordinal() &gt;= 14
    and user.friends.count &lt; 5
    and not errors %}
    &lt;div class="tip"&gt; ... &lt;/div&gt;
{% endif %}
</code></pre>

<p>Of course this does not work in Django. Django template engine&#8217;s <code>if</code> doesn&#8217;t have greater-than-or-equal operator, less-than operator and can not combine with truth testing (Instead has a seperate <code>ifequal</code> statement for truth testing). There are two workarounds;</p>

<ol>
<li><p>We calculate conditions at the <code>view</code> and pass them as simple boolean values.</p>

<pre><code>{% if user_registered_for_at_least_two_weeks
    and user_has_less_than_five_friends
    and no_errors %}
    &lt;div class="tip"&gt; ... &lt;/div&gt;
{% endif %}
</code></pre></li>
<li><p>We pass <code>user</code> reference and add checking functions to the models.</p>

<pre><code>{% if user.registeredAtLeastTwoWeeksAgo
    and user.hasLessThan5Friends %}
    {% ifequal errors None %}
        &lt;div class="tip"&gt; ... &lt;/div&gt;
    {% endif %}
{% endif %}
</code></pre></li>
</ol>

<p>The first one is actually not a solution, since we calculate the conditions in the <code>view</code> the presentation code is spanning both layers. The second workaround allows us to decouple the <code>template</code> and the <code>view</code> but adding more and more functions on models for such simple operations is just displacing the problem.</p>

<p>As far as I understand Django template engine has very simple control flow functionality for a reason. To ensure logic stays in the view; limit functionality in the template (to truth testing and equality testing only). But eventually you want a somewhat complex template and either the <code>view</code> or the <code>model</code> gets cluttered.</p>

<p>The first sample, the one with the complex if, is <a href="http://jinja.pocoo.org/">jinja</a> code. It&#8217;s conditional staments are almost as powerful as Python. This allows bad programming of course. You can do almost everything you are supposed to do in the <code>view</code>. But you if you follow decoupling principle you can have your code working, clean and maintanable.</p>

<p>I think Django is a special project (as an open source project, like <a href="http://www.blender.org/">Blender</a>, like <a href="http://www.inkscape.org/">Inkscape</a> in this sense). If we look carefully there are many lessons to be learned. Both in the API level and in the source code itself. I try to learn as much as possible from Django. But on my personal projects I would like to take full advantage of the expressive power of jinja (and <a href="http://www.sqlalchemy.org/">sqlalchemy</a> similarly). I try to assemble best components available, but I also do my best to follow best practises (learned from Django or other sources).</p>

<p>If you are considering Python for web development, I would say <strong>learn Django first</strong>. And then <strong>go ahead and study other frameworks and libraries</strong>. Python is extremely powerful and suits web development well. Once you found the setup (framework or whatever) that works best for you, I am sure you will enjoy it.</p>

<hr />

<p>1: There are different interpretations of MVC model. What happens in each layer might slightly change depending on the application type and of course implementors.</p>

<p>2: I know these line breaks look stupid. But it blows the page away otherwise.</p>
<div><a class="addthis_button" href="http://www.muhuk.com//addthis.com/bookmark.php?v=250" addthis:url='http://www.muhuk.com/2008/07/freedom-is-power/' addthis:title='Freedom is Power '><img src="//cache.addthis.com/cachefly/static/btn/v2/lg-share-en.gif" width="125" height="16" alt="Bookmark and Share" style="border:0"/></a></div><p>Related posts:<ol>
<li><a href='http://www.muhuk.com/2010/09/i-am-discontinuing-telvee/' rel='bookmark' title='I Am Discontinuing Telvee'>I Am Discontinuing Telvee</a></li>
<li><a href='http://www.muhuk.com/2011/06/pycon-apac-optimizing-media-performance-with-django_compressor/' rel='bookmark' title='My PyCon APAC 2011 Presentation: Optimizing Media Performance with django_compressor'>My PyCon APAC 2011 Presentation: Optimizing Media Performance with django_compressor</a></li>
<li><a href='http://www.muhuk.com/2011/11/working-with-files-in-django/' rel='bookmark' title='Working with files in Django &#8211; Part 1'>Working with files in Django &#8211; Part 1</a></li>
</ol></p> <p><a href="http://www.muhuk.com/?flattrss_redirect&amp;id=5&amp;md5=4530dc91c43bf1256690afd1090440a2" title="Flattr" target="_blank"><img src="http://www.muhuk.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.muhuk.com/2008/07/freedom-is-power/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<atom:link rel="payment" href="http://www.muhuk.com/?flattrss_redirect&amp;id=5&amp;md5=4530dc91c43bf1256690afd1090440a2" type="text/html" />
	</item>
	</channel>
</rss>

