<?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>Ben Jao Ming &#187; django</title>
	<atom:link href="http://overtag.dk/wordpress/category/computers/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://overtag.dk/wordpress</link>
	<description>101% objective... always</description>
	<lastBuildDate>Thu, 11 Apr 2013 10:24:53 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Testing and tracking down Warnings in Django</title>
		<link>http://overtag.dk/wordpress/2013/03/tracking-down-warnings-in-django/</link>
		<comments>http://overtag.dk/wordpress/2013/03/tracking-down-warnings-in-django/#comments</comments>
		<pubDate>Tue, 05 Mar 2013 10:32:41 +0000</pubDate>
		<dc:creator>benjamin</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://overtag.dk/wordpress/?p=365</guid>
		<description><![CDATA[Warnings are often suppressed through many layers of control mechanisms in Python and Django. However, you should really be aware of these and clean them up once in a while! In other cases, the Warnings reflect an inconsistent state, such &#8230; <a href="http://overtag.dk/wordpress/2013/03/tracking-down-warnings-in-django/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Warnings are often suppressed through many layers of control mechanisms in Python and Django. However, you should really be aware of these and clean them up once in a while!</p>
<p>In other cases, the Warnings reflect an inconsistent state, such as if you are mixing naive and timezone-aware variables. It can be a real pain to track down <code>RuntimeWarning</code> because it doesn&#8217;t leave a nice stack trace. The scenario could be that you have assigned a naive <code>DateTime</code> to a field, and the db layer is complaining at runtime.</p>
<p>However, you can run python in a mode where Warning-types raise exceptions with full stack traces. Use the following syntax:</p>
<pre>python -W error:"":RuntimeWarning:django.db.models.fields:0 manage.py runserver</pre>
<ul>
<li>&#8216;error&#8217; means that python should raise an exception &#8211; this is what we want!</li>
<li>&#8216;RuntimeWarning&#8217; means to trigger when such is raised &#8211; you can also simply put &#8216;Warning&#8217; to trigger for all Warning types.</li>
<li>&#8216;django.db.models.fields&#8217; means activate for this module (you need the full path). Notice that simply putting &#8216;django&#8217; does *not* activate for all of django, you need to put the specific module or simply &#8216;&#8221;"&#8216; to enable for all of Python (which might render some interesting Warning goodies that you have never seen!).</li>
<li>&#8217;0&#8242; means any line (you probably don&#8217;t need)</li>
</ul>
<p>You can read more in Python Documentation chapter: <a href="http://docs.python.org/2/library/warnings.html">Warning Control</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://overtag.dk/wordpress/2013/03/tracking-down-warnings-in-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Django: Log and block brute force attempts</title>
		<link>http://overtag.dk/wordpress/2013/02/django-log-and-block-brute-force-attempts/</link>
		<comments>http://overtag.dk/wordpress/2013/02/django-log-and-block-brute-force-attempts/#comments</comments>
		<pubDate>Tue, 26 Feb 2013 17:12:14 +0000</pubDate>
		<dc:creator>benjamin</dc:creator>
				<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://overtag.dk/wordpress/?p=363</guid>
		<description><![CDATA[Here is a very simple mechanism for wrapping a decorator around your views to protect them against brute force attempts. For instance, if you have a secret file download available only with the right secret (/view/id/secret-hash/), you expose your view &#8230; <a href="http://overtag.dk/wordpress/2013/02/django-log-and-block-brute-force-attempts/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Here is a very simple mechanism for wrapping a decorator around your views to protect them against brute force attempts. For instance, if you have a secret file download available only with the right secret (/view/id/secret-hash/), you expose your view to simple brute force attempts.</p>
<p>Simply put, this decorator will log a 404 response object or Http404 exception, count pr. IP and return <code>status=400</code> and send you an email whenever a new block is put into place.</p>
<h2>Model</h2>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> IllegalLookup<span style="color: black;">&#40;</span>LogModifications<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Log and block illegal lookups&quot;&quot;&quot;</span>
    created <span style="color: #66cc66;">=</span> models.<span style="color: black;">DateTimeField</span><span style="color: black;">&#40;</span>
        verbose_name<span style="color: #66cc66;">=</span>_<span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'created'</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
        auto_now_add <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span><span style="color: #66cc66;">,</span>
    <span style="color: black;">&#41;</span>
    modified <span style="color: #66cc66;">=</span> models.<span style="color: black;">DateTimeField</span><span style="color: black;">&#40;</span>
        verbose_name<span style="color: #66cc66;">=</span>_<span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'created'</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
        auto_now <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span><span style="color: #66cc66;">,</span>
    <span style="color: black;">&#41;</span>
    ip_address <span style="color: #66cc66;">=</span> models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>
        max_length<span style="color: #66cc66;">=</span><span style="color: #ff4500;">16</span><span style="color: #66cc66;">,</span>
        null<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: #66cc66;">,</span>
        blank<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: #66cc66;">,</span>
        verbose_name<span style="color: #66cc66;">=</span>_<span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'IP address'</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
    <span style="color: black;">&#41;</span>
    path <span style="color: #66cc66;">=</span> models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>
        max_length<span style="color: #66cc66;">=</span><span style="color: #ff4500;">255</span><span style="color: #66cc66;">,</span>
        null<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: #66cc66;">,</span>
        blank<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: #66cc66;">,</span>
        verbose_name<span style="color: #66cc66;">=</span>_<span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'path'</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
        help_text<span style="color: #66cc66;">=</span>_<span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'First attempted path is always logged'</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
    <span style="color: black;">&#41;</span>
    count <span style="color: #66cc66;">=</span> models.<span style="color: black;">PositiveIntegerField</span><span style="color: black;">&#40;</span>
        default<span style="color: #66cc66;">=</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span>
    <span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #66cc66;">@</span><span style="color: #008000;">classmethod</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> log_lookup<span style="color: black;">&#40;</span>cls<span style="color: #66cc66;">,</span> ip_address<span style="color: #66cc66;">,</span> path<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            now <span style="color: #66cc66;">=</span> timezone.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            expired <span style="color: #66cc66;">=</span> now - timedelta<span style="color: black;">&#40;</span>minutes<span style="color: #66cc66;">=</span>settings.<span style="color: black;">BLOCK_EXPIRY</span><span style="color: black;">&#41;</span>
            lookup <span style="color: #66cc66;">=</span> cls.<span style="color: black;">objects</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>ip_address<span style="color: #66cc66;">=</span>ip_address<span style="color: #66cc66;">,</span>
                modified__gte<span style="color: #66cc66;">=</span>expired<span style="color: black;">&#41;</span>
            lookup.<span style="color: black;">count</span> +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span>
            lookup.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> cls.<span style="color: black;">DoesNotExist</span>:
            <span style="color: #808080; font-style: italic;"># Delete old entries first</span>
            cls.<span style="color: black;">objects</span>.<span style="color: #008000;">filter</span><span style="color: black;">&#40;</span>ip_address<span style="color: #66cc66;">=</span>ip_address<span style="color: black;">&#41;</span>.<span style="color: black;">delete</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            lookup <span style="color: #66cc66;">=</span> cls.<span style="color: black;">objects</span>.<span style="color: black;">create</span><span style="color: black;">&#40;</span>ip_address<span style="color: #66cc66;">=</span>ip_address<span style="color: #66cc66;">,</span>
                path<span style="color: #66cc66;">=</span>path<span style="color: black;">&#41;</span>
            lookup.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #66cc66;">@</span><span style="color: #008000;">classmethod</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> is_blocked<span style="color: black;">&#40;</span>cls<span style="color: #66cc66;">,</span> ip_address<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            now <span style="color: #66cc66;">=</span> timezone.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            expired <span style="color: #66cc66;">=</span> now - timedelta<span style="color: black;">&#40;</span>minutes<span style="color: #66cc66;">=</span>settings.<span style="color: black;">BLOCK_EXPIRY</span><span style="color: black;">&#41;</span>
            lookup <span style="color: #66cc66;">=</span> cls.<span style="color: black;">objects</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>ip_address<span style="color: #66cc66;">=</span>ip_address<span style="color: #66cc66;">,</span>
                modified__gte<span style="color: #66cc66;">=</span>expired<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> lookup.<span style="color: black;">count</span> <span style="color: #66cc66;">==</span> settings.<span style="color: black;">BLOCK_ATTEMPTS</span>:
                mail_admins<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;IP blocked&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;{0} is now blocked, IllegalLookup id: {1}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>ip_address<span style="color: #66cc66;">,</span> lookup.<span style="color: #008000;">id</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> lookup.<span style="color: black;">count</span> <span style="color: #66cc66;">&gt;</span> settings.<span style="color: black;">BLOCK_ATTEMPTS</span>:
                <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> cls.<span style="color: black;">DoesNotExist</span>:
            <span style="color: #ff7700;font-weight:bold;">pass</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span></pre></td></tr></table></div>

<h2>Decorator</h2>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> log_and_block<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _log_and_block<span style="color: black;">&#40;</span>request<span style="color: #66cc66;">,</span> *args<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>:
        remote_ip <span style="color: #66cc66;">=</span> request.<span style="color: black;">META</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'REMOTE_ADDR'</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> IllegalLookup.<span style="color: black;">is_blocked</span><span style="color: black;">&#40;</span>remote_ip<span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span><span style="color: #483d8b;">'%s is blocked'</span> % remote_ip<span style="color: #66cc66;">,</span>
                status<span style="color: #66cc66;">=</span><span style="color: #ff4500;">400</span><span style="color: black;">&#41;</span>
&nbsp;
        is_404 <span style="color: #66cc66;">=</span> <span style="color: #008000;">False</span>
        is_exception <span style="color: #66cc66;">=</span> <span style="color: #008000;">False</span>
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            return_object <span style="color: #66cc66;">=</span> func<span style="color: black;">&#40;</span>request<span style="color: #66cc66;">,</span> *args<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> return_object.<span style="color: black;">status_code</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">404</span>:
                is_404 <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> Http404:
            is_404 <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span>
            is_exception <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> is_404:
            <span style="color: #ff7700;font-weight:bold;">if</span> remote_ip:
                IllegalLookup.<span style="color: black;">log_lookup</span><span style="color: black;">&#40;</span>remote_ip<span style="color: #66cc66;">,</span>
                    request.<span style="color: black;">META</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'PATH_INFO'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
            <span style="color: #ff7700;font-weight:bold;">if</span> is_exception:
                <span style="color: #ff7700;font-weight:bold;">raise</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">return</span> return_object
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> _log_and_block</pre></td></tr></table></div>

<h2>Usage</h2>
<p>Now, simply wrap the decorator around your view:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">@</span>log_and_block
<span style="color: #ff7700;font-weight:bold;">def</span> my_view<span style="color: black;">&#40;</span>request<span style="color: #66cc66;">,</span> <span style="color: #008000;">id</span><span style="color: #66cc66;">,</span> secret_hash<span style="color: black;">&#41;</span>:
    <span style="color: #008000;">object</span> <span style="color: #66cc66;">=</span> get_object_or_404<span style="color: black;">&#40;</span>models.<span style="color: black;">MyModel</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">id</span><span style="color: #66cc66;">=</span><span style="color: #008000;">id</span><span style="color: #66cc66;">,</span> secret_hash<span style="color: #66cc66;">=</span>secret_hash<span style="color: black;">&#41;</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://overtag.dk/wordpress/2013/02/django-log-and-block-brute-force-attempts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Making the django foreign key admin widget more useful</title>
		<link>http://overtag.dk/wordpress/2012/06/making-the-django-foreign-key-admin-widget-more-useful/</link>
		<comments>http://overtag.dk/wordpress/2012/06/making-the-django-foreign-key-admin-widget-more-useful/#comments</comments>
		<pubDate>Thu, 14 Jun 2012 22:28:59 +0000</pubDate>
		<dc:creator>benjamin</dc:creator>
				<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://overtag.dk/wordpress/?p=318</guid>
		<description><![CDATA[Thanks to a user at Django-snippets, I was able to quickly create an app containing a widget for displaying icons along side the normal related widget for foreignkey fields. The result looks like this: It&#8217;s pretty easy to use. Check &#8230; <a href="http://overtag.dk/wordpress/2012/06/making-the-django-foreign-key-admin-widget-more-useful/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Thanks to a user at Django-snippets, I was able to quickly create an app containing a widget for displaying icons along side the normal related widget for foreignkey fields.</p>
<p>The result looks like this:</p>
<p><img src="http://overtag.dk/wordpress/wp-content/uploads/screenshot4.png" alt="" title="screenshot4" width="263" height="47" class="alignnone size-full wp-image-319" /></p>
<p>It&#8217;s pretty easy to use.</p>
<p><a href="https://github.com/benjaoming/django-relatedadminwidget">Check it out on Github!</a></p>
]]></content:encoded>
			<wfw:commentRss>http://overtag.dk/wordpress/2012/06/making-the-django-foreign-key-admin-widget-more-useful/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Overriding change_form.html and accessing the object instance</title>
		<link>http://overtag.dk/wordpress/2012/04/overriding-change_form-html-and-accessing-the-object-instance/</link>
		<comments>http://overtag.dk/wordpress/2012/04/overriding-change_form-html-and-accessing-the-object-instance/#comments</comments>
		<pubDate>Tue, 03 Apr 2012 09:55:39 +0000</pubDate>
		<dc:creator>benjamin</dc:creator>
				<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://overtag.dk/wordpress/?p=304</guid>
		<description><![CDATA[Here&#8217;s an example for a custom change_form.html located in app/templates/admin/appname/modelname/change_form.html &#8211; and the cool thing is that it accesses the actual instance of the object, which I found to be very convenient and undocumented. If you want it to be &#8230; <a href="http://overtag.dk/wordpress/2012/04/overriding-change_form-html-and-accessing-the-object-instance/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s an example for a custom change_form.html located in app/templates/admin/appname/modelname/change_form.html &#8211; and the cool thing is that it accesses the actual instance of the object, which I found to be very convenient and undocumented. If you want it to be more explicit than access through the builtin context variable adminform.form.instance, you can also make your own <a href="https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#django.contrib.admin.ModelAdmin.change_view" target="_blank">change_view</a>.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">{% extends &quot;admin/change_form.html&quot; %}
&nbsp;
{% block object-tools %}
  {{ block.super }}
  &lt;h2&gt;{{ adminform.form.instance }}&lt;/h2&gt;
{% endblock %}</pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://overtag.dk/wordpress/2012/04/overriding-change_form-html-and-accessing-the-object-instance/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>django-cms 2.0.2 and Django 1.2 &#8211; 1.3</title>
		<link>http://overtag.dk/wordpress/2012/02/django-cms-2-0-2-and-django-1-2-1-3/</link>
		<comments>http://overtag.dk/wordpress/2012/02/django-cms-2-0-2-and-django-1-2-1-3/#comments</comments>
		<pubDate>Wed, 01 Feb 2012 14:56:33 +0000</pubDate>
		<dc:creator>benjamin</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[django-cms]]></category>

		<guid isPermaLink="false">http://overtag.dk/wordpress/?p=280</guid>
		<description><![CDATA[If you are running an old version of django-cms, you can still upgrade Django. I would strongly suggest doing this since it&#8217;s very uncomplicated. However, if you are running django-cms 2.0, you should first upgrade to 2.0.2 and run the &#8230; <a href="http://overtag.dk/wordpress/2012/02/django-cms-2-0-2-and-django-1-2-1-3/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>If you are running an old version of django-cms, you can still upgrade Django. I would strongly suggest doing this since it&#8217;s very uncomplicated. However, if you are running django-cms 2.0, you should first upgrade to 2.0.2 and run the South migrations, which is also totally uncomplicated.</p>
<p>django-cms 1.x are most likely stuck on older versions of Django as well. I did once try to get them running on new Django versions but gave up.</p>
<p>Basically this guide just fixes a little bug in admin/pageadmin.py and a few issues regarding a missing csrf_token in the templates. It also means that django-cms 2.0.2 becomes SSL compatible. This is not backwards-compatible, however, so if you apply this stuff, your django-cms will no longer work with Django 1.1.</p>
<p>After upgrading to django 1.3.1 (also tested on 1.2.X btw), you need to make the following corrections manually in your django-cms installation.</p>
<p>1) Edit cms/admin/pageadmin.py, line 59 to say:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    exclude <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>2) Edit cms/templates/admin/cms/page/plugin_change_form.html, line 77, by adding the csrf_token tag:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">&lt;form id=&quot;{{ opts.module_name }}_form&quot; action=&quot;{{ form_url }}&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;{% block form_top %}{% endblock %}
{% csrf_token %}</pre></td></tr></table></div>

<p>2.1) Do the same in cms/templates/admin/cms/page/change_form.html, line 99:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">&lt;form id=&quot;page_form&quot; action=&quot;?language={{ language }}{%if request.GET.target %}&amp;amp;target={{ request.GET.target }}{% endif %}&amp;amp;{%if request.GET.target %}position={{ request.GET.position }}{% endif %}&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;{% block form_top %}{% endblock %}
{% csrf_token %}</pre></td></tr></table></div>

<p>2.2) Do the same in cms/templates/admin/cms/page/dialog/base.html, line 5:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">                {% block form %}{% if form %}&lt;form id=&quot;{{ dialog_id }}-form&quot;&gt;{% csrf_token %}{{ form.as_p }}{% endif %}{% endblock %}</pre></td></tr></table></div>

<p>3) Ensure that you have CsrfViewMiddleware and CsrfResponseMiddleware installed. Your settings.py should contain something like this:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">MIDDLEWARE_CLASSES <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span>
    <span style="color: #483d8b;">'django.middleware.common.CommonMiddleware'</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'django.contrib.sessions.middleware.SessionMiddleware'</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'django.middleware.csrf.CsrfViewMiddleware'</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'django.middleware.csrf.CsrfResponseMiddleware'</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'django.contrib.auth.middleware.AuthenticationMiddleware'</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'django.contrib.messages.middleware.MessageMiddleware'</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'cms.middleware.page.CurrentPageMiddleware'</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'cms.middleware.user.CurrentUserMiddleware'</span><span style="color: #66cc66;">,</span>
<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>5) Finally, you need to bring in a file from later django-cms, csrf.js (<a href="https://github.com/divio/django-cms/blob/1dff25788a30b9e6e5c8cada405db60ae74764b7/cms/media/cms/js/csrf.js">github revision that I used</a>). Place it in media/cms/js/.</p>
<p>6) Add csrf.js to cms/admin/widgets.py in PluginEditor.media, around line 17:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">class</span> Media:
        js <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>join<span style="color: black;">&#40;</span>settings.<span style="color: black;">CMS_MEDIA_URL</span><span style="color: #66cc66;">,</span> path<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> path <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span>
            <span style="color: #483d8b;">'js/lib/jquery.js'</span><span style="color: #66cc66;">,</span>
            <span style="color: #483d8b;">'js/lib/ui.core.js'</span><span style="color: #66cc66;">,</span>
            <span style="color: #483d8b;">'js/lib/ui.sortable.js'</span><span style="color: #66cc66;">,</span>
            <span style="color: #483d8b;">'js/csrf.js'</span><span style="color: #66cc66;">,</span>
            <span style="color: #483d8b;">'js/plugin_editor.js'</span><span style="color: #66cc66;">,</span>
        <span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>7) Add this around line 97 in cms/media/cms/js/change_list.js:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="js" style="font-family:monospace;">	$(document).ready(function() {
		$.fn.cmsPatchCSRF();
	    selected_page = false;
	    action = false;</pre></td></tr></table></div>

<p><span>8</span>) Do the same in cms/media/cms/js/plugin_editor.js at the first line:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="js" style="font-family:monospace;">$(document).ready(function() {
  	$.fn.cmsPatchCSRF();</pre></td></tr></table></div>

<p><span>9</span>) Do the same in cms/plugins/text/templates/cms/plugins/widgets/wymeditor.html line 12:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="js" style="font-family:monospace;">$(document).ready(function() {
  	$.fn.cmsPatchCSRF();</pre></td></tr></table></div>

<p><span>10</span>) &#8230;and also in cms/plugins/text/templates/cms/plugins/widgets/wymeditor.html line 2, insert:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="js" style="font-family:monospace;">&lt;script type=&quot;text/javascript&quot; src=&quot;{{ CMS_MEDIA_URL }}js/csrf.js&quot;&gt;&lt;/script&gt;</pre></td></tr></table></div>

<p>11) In /cms/templates/admin/cms/page/change_list.html you should also include csrf.js, around line 33:</p>
<pre class="js">&lt;script type="text/javascript" src="{{ CMS_MEDIA_URL }}js/csrf.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="{{ CMS_MEDIA_URL }}js/change_list.js"&gt;&lt;/script&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://overtag.dk/wordpress/2012/02/django-cms-2-0-2-and-django-1-2-1-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stopforumspam Django Middleware</title>
		<link>http://overtag.dk/wordpress/2011/09/stopforumspam-django-middleware/</link>
		<comments>http://overtag.dk/wordpress/2011/09/stopforumspam-django-middleware/#comments</comments>
		<pubDate>Sun, 18 Sep 2011 03:07:32 +0000</pubDate>
		<dc:creator>benjamin</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://overtag.dk/wordpress/?p=269</guid>
		<description><![CDATA[I have created a new Django app for keeping out spammers on the basis of data collected by stopforumspam.com. Read all about it here » It&#8217;s free, open source, and I hope people will make it better on github.]]></description>
				<content:encoded><![CDATA[<p><a href="http://overtag.dk/wordpress/wp-content/uploads/Screenshot.png"><img class="alignright size-thumbnail wp-image-272" title="Screenshot" src="http://overtag.dk/wordpress/wp-content/uploads/Screenshot-150x150.png" alt="" width="150" height="150" /></a>I have created a new Django app for keeping out spammers on the basis of data collected by stopforumspam.com. <a title="Stopforumspam Django Middleware" href="http://overtag.dk/wordpress/projects/stopforumspam-django-middleware/">Read all about it here »</a></p>
<p>It&#8217;s free, open source, and I hope people will make it better on github.</p>
]]></content:encoded>
			<wfw:commentRss>http://overtag.dk/wordpress/2011/09/stopforumspam-django-middleware/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Changing the Django Admin site title</title>
		<link>http://overtag.dk/wordpress/2010/04/changing-the-django-admin-site-title/</link>
		<comments>http://overtag.dk/wordpress/2010/04/changing-the-django-admin-site-title/#comments</comments>
		<pubDate>Fri, 02 Apr 2010 23:45:52 +0000</pubDate>
		<dc:creator>benjamin</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[django-admin]]></category>
		<category><![CDATA[translation]]></category>

		<guid isPermaLink="false">http://overtag.dk/wordpress/?p=191</guid>
		<description><![CDATA[Often the Django Admin should look a little different for the sake of your users or for the sake of yourself (running multiple django sites with identical looks and titles can be such a pain). Often users don&#8217;t know what &#8230; <a href="http://overtag.dk/wordpress/2010/04/changing-the-django-admin-site-title/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Often the Django Admin should look a little different for the sake of your users or for the sake of yourself (running multiple django sites with identical looks and titles can be such a pain). Often users don&#8217;t know what Django is, and it takes ages to explain, and even after that they have no clue. Also, often my administration has nothing to do with a website, so I don&#8217;t want the text &#8220;Site administration&#8221;.</p>
<p>First of all, you wanna add <strong>templates/admin/base_site.html</strong> to your project. This file can safely be overwritten, since it&#8217;s a file that the django devs have intended for the exact purpose of customizing your admin site a bit. Here&#8217;s an example of what to put in the file:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">{% extends &quot;admin/base.html&quot; %}
{% load i18n %}
&nbsp;
{% block title %}{{ title }} | {% trans 'Some Organisation' %}{% endblock %}
&nbsp;
{% block branding %}
&lt;style type=&quot;text/css&quot;&gt;
  #header
  {
    /* your style here */
  }
&lt;/style&gt;
&lt;h1 id=&quot;site-name&quot;&gt;{% trans 'Organisation Website' %}&lt;/h1&gt;
{% endblock %}
&nbsp;
{% block nav-global %}{% endblock %}</pre></td></tr></table></div>

<p>This is common practice. But I noticed after this that I was still left with an annoying &#8220;Site Administration&#8221; on the main admin index page. And this string was not inside any of the template, but rather set inside the admin view. Luckily it&#8217;s quite easy to change. Assuming your language is set to English, run the following commands from your project directory:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">mkdir</span> locale
$ .<span style="color: #000000; font-weight: bold;">/</span>manage.py makemessages <span style="color: #660033;">-l</span> en</pre></td></tr></table></div>

<p>Now open up the file <strong>locale/en/LC_MESSAGES/django.po</strong> and add two lines after the header information (the last two lines of this example)</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="gettext" style="font-family:monospace;"><span style="color: #ff0000;">&quot;Project-Id-Version: PACKAGE VERSION<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
<span style="color: #ff0000;">&quot;Report-Msgid-Bugs-To: <span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
<span style="color: #ff0000;">&quot;POT-Creation-Date: 2010-04-03 03:25+0200<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
<span style="color: #ff0000;">&quot;PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
<span style="color: #ff0000;">&quot;Last-Translator: FULL NAME &lt;EMAIL@ADDRESS&gt;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
<span style="color: #ff0000;">&quot;Language-Team: LANGUAGE &lt;LL@li.org&gt;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
<span style="color: #ff0000;">&quot;MIME-Version: 1.0<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
<span style="color: #ff0000;">&quot;Content-Type: text/plain; charset=UTF-8<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
<span style="color: #ff0000;">&quot;Content-Transfer-Encoding: 8bit<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">msgid</span> <span style="color: #ff0000;">&quot;Site administration&quot;</span>
<span style="color: #000000; font-weight: bold;">msgstr</span> <span style="color: #ff0000;">&quot;Main administration index&quot;</span></pre></td></tr></table></div>

<p>After this, remember to run this and reload your project&#8217;s server:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666;">$ </span>.<span style="color: #000000; font-weight: bold;">/</span>manage.py compilemessages</pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://overtag.dk/wordpress/2010/04/changing-the-django-admin-site-title/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Django tip: Automatic logins</title>
		<link>http://overtag.dk/wordpress/2010/02/django-tip-automatic-logins/</link>
		<comments>http://overtag.dk/wordpress/2010/02/django-tip-automatic-logins/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 13:21:56 +0000</pubDate>
		<dc:creator>benjamin</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[authenticate]]></category>
		<category><![CDATA[login]]></category>

		<guid isPermaLink="false">http://overtag.dk/wordpress/?p=182</guid>
		<description><![CDATA[In the Django documentation we see the following: When you&#8217;re manually logging a user in, you must call authenticate() before you call login(). That&#8217;s all really nice, because it makes sure that all your authentication backends are tried out; but &#8230; <a href="http://overtag.dk/wordpress/2010/02/django-tip-automatic-logins/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>In the Django documentation we see the following:</p>
<blockquote><p>When you&#8217;re manually logging a user in, you must call <strong>authenticate()</strong> before you call<strong> login()</strong>.</p></blockquote>
<p>That&#8217;s all really nice, because it makes sure that all your authentication backends are tried out; but if you want a really quick remedy for getting the job done, then you&#8217;ll need to set the <em>user.backend</em> property to the specific backend that authenticated the user. Beware that the Django developers can change these requirements. I wanted this to avoid writing my own backend, so I did this to log users in via a special view accepting a hash from the URL (from an e-mail that had a link that&#8217;d automatically log a user in). This could also become useful if you want to <em>become</em> a different user.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> get_hash<span style="color: black;">&#40;</span>s<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">import</span> hashlib
    m <span style="color: #66cc66;">=</span> hashlib.<span style="color: #dc143c;">md5</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    m.<span style="color: black;">update</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>s<span style="color: black;">&#41;</span> + settings.<span style="color: black;">LOGIN_SECRET</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>m.<span style="color: black;">hexdigest</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> auto_login<span style="color: black;">&#40;</span>request<span style="color: #66cc66;">,</span> user_id<span style="color: #66cc66;">,</span> secret<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #dc143c;">user</span> <span style="color: #66cc66;">=</span> get_object_or_404<span style="color: black;">&#40;</span>User<span style="color: #66cc66;">,</span> <span style="color: #008000;">id</span><span style="color: #66cc66;">=</span>user_id<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> secret <span style="color: #66cc66;">==</span> get_hash<span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>user_id<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> Http404<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #dc143c;">user</span>.<span style="color: black;">backend</span> <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;django.contrib.auth.backends.ModelBackend&quot;</span>
    login<span style="color: black;">&#40;</span>request<span style="color: #66cc66;">,</span> <span style="color: #dc143c;">user</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponseRedirect<span style="color: black;">&#40;</span>reverse<span style="color: black;">&#40;</span><span style="color: #483d8b;">'frontpage'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p><strong>BEWARE!</strong><br />
I strongly suggest that you don&#8217;t log any superusers in this way. You could add a conditional statement <em>not user.is_superuser</em> or similar.</p>
]]></content:encoded>
			<wfw:commentRss>http://overtag.dk/wordpress/2010/02/django-tip-automatic-logins/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Django localized date template filter</title>
		<link>http://overtag.dk/wordpress/2009/07/django-localized-date-template-filter/</link>
		<comments>http://overtag.dk/wordpress/2009/07/django-localized-date-template-filter/#comments</comments>
		<pubDate>Fri, 10 Jul 2009 22:24:13 +0000</pubDate>
		<dc:creator>benjamin</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[template filter]]></category>

		<guid isPermaLink="false">http://overtag.dk/wordpress/?p=155</guid>
		<description><![CDATA[UPDATE! This is going to be redundant in Django 1.2, in which you can add DATE_FORMAT to your django.po files. I&#8217;ve often been frustrated that using settings.DATE_FORMAT does not give a localized date. Granted that the name of a month &#8230; <a href="http://overtag.dk/wordpress/2009/07/django-localized-date-template-filter/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><strong>UPDATE!</strong> This is going to be redundant in Django 1.2, in which you can add DATE_FORMAT to your django.po files.</p>
<p>I&#8217;ve often been frustrated that using <strong>settings.DATE_FORMAT</strong> does not give a localized date. Granted that the name of a month may be localized, but the format string does not change. So let&#8217;s start out by modifying <strong>settings.py</strong>. We wrap our default date format in a <b>ugettext</b> so the makemessages command will detect it, and we need to make it a dummy function, because the i18n library cannot be imported in settings.py due to circularity (it depends on settings.py).</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">ugettext <span style="color: #66cc66;">=</span> <span style="color: #ff7700;font-weight:bold;">lambda</span> s: s
DATE_FORMAT <span style="color: #66cc66;">=</span> ugettext<span style="color: black;">&#40;</span><span style="color: #483d8b;">'N j, Y'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Run compilemessages and type in your localized date formats. Now we need a template filter that uses a localized format for calling the Django date format function. This is really simple:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">template</span>.<span style="color: black;">defaultfilters</span> <span style="color: #ff7700;font-weight:bold;">import</span> stringfilter
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">utils</span> <span style="color: #ff7700;font-weight:bold;">import</span> dateformat
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">utils</span>.<span style="color: black;">translation</span> <span style="color: #ff7700;font-weight:bold;">import</span> ugettext
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
&nbsp;
<span style="color: #66cc66;">@</span>register.<span style="color: #008000;">filter</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> localdate<span style="color: black;">&#40;</span>value<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Format date with localized date format&quot;&quot;&quot;</span>
    format <span style="color: #66cc66;">=</span> ugettext<span style="color: black;">&#40;</span>settings.<span style="color: black;">DATE_FORMAT</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> dateformat.<span style="color: black;">format</span><span style="color: black;">&#40;</span>value<span style="color: #66cc66;">,</span> format<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>And done. Using the filter is straight forward:</p>
<p><code><br />
Date: {{ my_date|localdate }}<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://overtag.dk/wordpress/2009/07/django-localized-date-template-filter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Presenting: django-simple-wiki</title>
		<link>http://overtag.dk/wordpress/2009/04/presenting-django-simple-wiki/</link>
		<comments>http://overtag.dk/wordpress/2009/04/presenting-django-simple-wiki/#comments</comments>
		<pubDate>Sun, 26 Apr 2009 23:52:57 +0000</pubDate>
		<dc:creator>benjamin</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[django application]]></category>
		<category><![CDATA[django-simple-wiki]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[wiki]]></category>

		<guid isPermaLink="false">http://overtag.dk/wordpress/?p=142</guid>
		<description><![CDATA[It was bothering me that all the wikis I tried, all had either errors, feature lacks, too many dependencies or were simply unmaintained. So I decided to create yet another one. Curiously, the third hit when googling &#8216;django wiki&#8217; is &#8230; <a href="http://overtag.dk/wordpress/2009/04/presenting-django-simple-wiki/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>It was bothering me that all the wikis I tried, all had either errors, feature lacks, too many dependencies or were simply unmaintained. So I decided to create yet another one. Curiously, the third hit when googling &#8216;django wiki&#8217; is <a href="http://showmedo.com/videotutorials/video?name=1100000">Create a wiki in 20 minutes</a>. Luckily that&#8217;s not really true, so all the PHP guys and MediaWiki can continue breathing. This took me several days.</p>
<blockquote style="font-size: 150%;"><p><strong><a href="http://code.google.com/p/django-simple-wiki/">Google Code project page</a></strong></p></blockquote>
<blockquote style="font-size: 150%;"><p><strong><a href="http://wikidemo.overtag.dk/">Demo website</a></strong></p></blockquote>
<p><strong>Hierarchy and relations</strong><br />
First of all, as in the Trac wiki system, I chose to create a system for hierarchy, meaning that it&#8217;s possible to create an article and then create sub-articles. The hierarchy does not support multiple inheritance, because it needs to be basis for the permission system. That&#8217;s where the relation system comes in place: All articles can contain symmetrical relations to any other articles in the hierarchy.</p>
<p><strong>Parsing</strong><br />
Python and Django supports Markdown pretty much out of the box, so it&#8217;s an obvious choice to use this for parsing. The HTML features of normal Markdown have been removed, so all HTML is escaped in django-simple-wiki. And parsing is static, so every time a revision is created, the contents are passed and stored. This means that the contents of the article itself are not supposed to be dynamic. On the other hand, it is desirable to avoid parsing contents for every page hit. The parsing area of the application is only a few lines of code, and can be expanded if further parsing needs to be done, or someone wants to replace Markdown completely. For instance, if no parsing is done and HTML escaping is disabled, the wiki becomes a very simple CMS.</p>
<p><strong>Curious issues</strong><br />
There are a few out standing problems:</p>
<ul>
<li>Permission system is related to User entries in the Django auth system. But maybe this is too much of an annoyance, if the project already has groups setup in the existing auth system. On the other hand, other users would be bothered to setup both wiki groups and user groups, if the permission system was linked to user groups. And directly linking articles to user groups would require wiki-related groups to be created directly in the auth system.</li>
<li>Since relations are symmetrical, what should happen if one article is locked, but a user modifies it&#8217;s relations by deleting them from related articles?</li>
<li>Title editing: The title can only be created once, since it is coupled to the &#8216;slug&#8217; of the article. A user can deliberately create a completely different title, which is fine, but should subsequent editing be allowed, which would add complexity to the revision system?</li>
<li>Article deletion: When an article is deleted from the backend it shouldn&#8217;t worry anyone. But if the feature is added to the frontend, we would want to handle maliciousness etc. But should we really store all these files and revisions? Should we alert admins, so they can do the final cleanup?</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://overtag.dk/wordpress/2009/04/presenting-django-simple-wiki/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
