<?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>Save the ions! &#187; Django</title>
	<atom:link href="http://savetheions.com/category/programming/python/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://savetheions.com</link>
	<description></description>
	<lastBuildDate>Fri, 25 Mar 2011 11:01:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Introducing (python-)caldav</title>
		<link>http://savetheions.com/2010/06/04/introducing-python-caldav/</link>
		<comments>http://savetheions.com/2010/06/04/introducing-python-caldav/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 19:35:22 +0000</pubDate>
		<dc:creator>cyril</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://savetheions.com/?p=187</guid>
		<description><![CDATA[During the last few days, I&#8217;ve been busy writing a CalDAV client library for work. This is a requirement because we are going to integrate calendars from various sources in one of our websites. CalDAV is clearly the way to go, but as far as libraries go, the only one I&#8217;ve been able to find [...]]]></description>
			<content:encoded><![CDATA[<p>During the last few days, I&#8217;ve been busy writing a CalDAV client library for work. This is a requirement because we are going to integrate calendars from various sources in one of our websites.</p>
<p>CalDAV is clearly the way to go, but as far as libraries go, the only one I&#8217;ve been able to find was <a href="http://trac.calendarserver.org/wiki/CalDAVClientLibrary" target="_blank">CalDAVClientLibrary</a>, which, quite frankly, scares me. I&#8217;m already familiar with CalendarServer, and I can&#8217;t qualify that as &#8220;lightweight&#8221;, &#8220;simple&#8221; or &#8220;easily installable&#8221;.</p>
<h1>CalDAV</h1>
<p>In case you don&#8217;t know what CalDAV is, it&#8217;s an extension to webdav for calendaring, and is defined in <a href="http://www.ietf.org/rfc/rfc4791.txt" target="_blank">rfc4791</a>. If you don&#8217;t feel like reading all of this, it&#8217;s mostly HTTP with XML requests and responses, but not always, which is why it gets kind of weird&#8230;</p>
<h2>Example requests</h2>
<p>Creating a calendar:</p>
<pre>
MKCOL /calendars/pythoncaldav-test HTTP/1.1
Host: example.com
Accept-Encoding: identity
Content-Length: 249

&lt;?xml version='1.0' encoding='utf-8'?>
&lt;D:mkcol xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:D="DAV:">
  &lt;D:set>
    &lt;D:prop>
      &lt;D:resourcetype>
        &lt;D:collection>
          &lt;C:calendar-collection/>
        &lt;/D:collection>
      &lt;/D:resourcetype>
      &lt;D:displayname>Yep</D:displayname>
    &lt;/D:prop>
  &lt;/D:set>
&lt;/D:mkcol>
</pre>
<p>Deleting a calendar:</p>
<pre>
DELETE /calendars/pythoncaldav-test HTTP/1.1
Host: example.com
Accept-Encoding: identity
</pre>
<h1>caldav</h1>
<p>The version I just released is the very beginning of the project: it has basic functionality, but lacks many things, such as error handling and full support for the protocol. The documentation also needs a lot more work.</p>
<h2>Example</h2>
<p>I tried keeping the API very simple, and close to what an ORM would be used like, here&#8217;s an example:</p>
<pre class="prettyprint">
import caldav
from caldav.lib.namespace import ns

# Principal url
url = "https://user:pass@hostname/user/Calendar"
vcal = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
UID:1234567890
DTSTAMP:20100510T182145Z
DTSTART:20100512T170000Z
DTEND:20100512T180000Z
SUMMARY:This is an event
END:VEVENT
END:VCALENDAR
"""

client = caldav.DAVClient(url)
principal = caldav.Principal(url)
calendars = principal.calendars()
if len(calendars) > 0:
    calendar = calendars[0]
    print "Using calendar", calendar

    print "Renaming"
    calendar.set_properties({ns("D", "displayname"): "Test calendar",})
    print calendar.get_properties([ns("D", "displayname"),])

    event = caldav.Event(client, data = vcal, parent = calendar).save()
    print "Event", event, "created"

    print "Looking for events after 2010-05-01"
    results = calendar.date_search("20100501T000000Z")
    for event in results:
        print "Found", event
</pre>
<h1>Links</h1>
<p>I released caldav and its documentation on pypi, and the code is on bitbucket:</p>
<ul>
<li>Pypi: <a href="http://pypi.python.org/pypi/caldav" target="_blank">http://pypi.python.org/pypi/caldav</a></li>
<li>Documentation: <a href="http://packages.python.org/caldav" target="_blank">http://packages.python.org/caldav</a></li>
<li>Bitbucket: <a href="http://bitbucket.org/cyrilrbt/caldav" target="_blank">http://bitbucket.org/cyrilrbt/caldav</a></li>
</ul>
<p>Contributions are welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://savetheions.com/2010/06/04/introducing-python-caldav/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Django Debug Toolbar</title>
		<link>http://savetheions.com/2010/04/12/django-debug-toolbar/</link>
		<comments>http://savetheions.com/2010/04/12/django-debug-toolbar/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 04:21:20 +0000</pubDate>
		<dc:creator>cyril</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://savetheions.com/?p=171</guid>
		<description><![CDATA[I wish for two things: That there was some kind of RT function with rss feeds (the only feature I like about twitter) That Django Debug Toolbar is merged in django 1.2+ &#160; via Planet GNOME BTW, I can&#8217;t believe no one else on Planet Django mentioned it yet!]]></description>
			<content:encoded><![CDATA[<p>I wish for two things:</p>
<ul>
<li>That there was some kind of RT function with rss feeds (the only feature I like about twitter)</li>
<li>That <a href="http://www.ogmaciel.com/?p=874">Django Debug Toolbar</a> is merged in django 1.2+</li>
</ul>
<p>&nbsp;</p>
<p>via <a href="http://planet.gnome.org/">Planet GNOME</a></p>
<p>BTW, I can&#8217;t believe no one else on Planet Django mentioned it yet!</p>
]]></content:encoded>
			<wfw:commentRss>http://savetheions.com/2010/04/12/django-debug-toolbar/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Modifying the regexp for usernames in django-admin</title>
		<link>http://savetheions.com/2010/03/14/modifying-the-regexp-for-usernames-in-django-admin/</link>
		<comments>http://savetheions.com/2010/03/14/modifying-the-regexp-for-usernames-in-django-admin/#comments</comments>
		<pubDate>Sun, 14 Mar 2010 23:08:34 +0000</pubDate>
		<dc:creator>cyril</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://savetheions.com/?p=114</guid>
		<description><![CDATA[About a month ago, I built a centralized authentication backend using django-roa for my company, AUF. It&#8217;s actually a cascading authentication system, since I copy locally (in Django&#8217;s own authentication system) the account, once validated. That was working just fine, until I tried adding some of my users&#8217; local accounts in different groups. The distant [...]]]></description>
			<content:encoded><![CDATA[<p>About a month ago, I built a centralized authentication backend using <a href="http://bitbucket.org/david/django-roa/" target="_blank">django-roa</a> for my company, <a href="http://auf.org/" target="_blank">AUF</a>. It&#8217;s actually a cascading authentication system, since I copy locally (in Django&#8217;s own authentication system) the account, once validated.</p>
<p>That was working just fine, until I tried adding some of my users&#8217; local accounts in different groups. The distant usernames follow the format <code>&lt;first_name&gt;.&lt;last_name&gt;</code>, and since Django doesn&#8217;t allow that, everytime I would try to save the user edit form in the admin interface, I would get an error message saying that the username format was invalid.</p>
<p>After looking around a bit, I found <a href="http://stackoverflow.com/questions/1214453/allowing-the-character-in-usernames-in-the-django-admin-interface" target="_blank">this</a> solution, which has been working great for me.</p>
<pre class="prettyprint">
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.contrib import admin

class UserCreationForm(UserCreationForm):
    username = forms.RegexField(label=_("Username"), max_length=30,
            regex=r"^[\w'\.\-]+\s?[\w'\.\-]+$")

class UserChangeForm(UserChangeForm):
    username = forms.RegexField(label=_("Username"), max_length=30,
            regex=r"^[\w'\.\-]+\s?[\w'\.\-]+$")

class UserProfileAdmin(UserAdmin):
    form = UserChangeForm
    add_form = UserCreationForm

admin.site.unregister(User)
admin.site.register(User, UserProfileAdmin)
</pre>
]]></content:encoded>
			<wfw:commentRss>http://savetheions.com/2010/03/14/modifying-the-regexp-for-usernames-in-django-admin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing django-exportateur</title>
		<link>http://savetheions.com/2010/02/15/introducing-django-exportateur/</link>
		<comments>http://savetheions.com/2010/02/15/introducing-django-exportateur/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 15:12:15 +0000</pubDate>
		<dc:creator>cyril</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://savetheions.com/?p=102</guid>
		<description><![CDATA[Exportateur? OK, this article is a bit late, but I think it&#8217;s still necessary to properly introduce a new project. At work last week, I had to write a generic way of exporting a QuerySet to csv, ods, and maybe some other format later on. Since I work at AUF, I frenched up the project&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<h1>Exportateur?</h1>
<p>OK, this article is a bit late, but I think it&#8217;s still necessary to properly introduce a new project.</p>
<p>At work last week, I had to write a generic way of exporting a QuerySet to csv, ods, and maybe some other format later on. Since I work at <a href="http://www.auf.org/" target="_blank">AUF</a>, I frenched up the project&#8217;s name.</p>
<h1>Why start from scratch?</h1>
<p>I&#8217;m pretty sure that there already are a few apps that do that, but since I still consider myself kind of new to django, I thought it would be a good learning exercise to write this app myself.</p>
<h1>The idea</h1>
<p>The files I had to generate needed to have a header that described each column, and the values needed to be clear (no ids, etc.)</p>
<p>I decided to add a method to get the object&#8217;s fields (attribute name as well as verbose name), and another one to get the attributes&#8217; values. That&#8217;s pretty much it for the <i>Django</i> part.</p>
<p>The last part of the project was to define a generic-enough method to export those fields in the file format we want. The file format is passed as a parameter so that it can be passed directly from the url.</p>
<h1>Have a look</h1>
<p>The code is now published on <a href="http://code.google.com/p/django-exportateur/" target="_blank">code.google.com</a>. Feedback is always welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://savetheions.com/2010/02/15/introducing-django-exportateur/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Logging your instances&#039; history in Django</title>
		<link>http://savetheions.com/2010/01/31/logging-your-instances-history-in-django/</link>
		<comments>http://savetheions.com/2010/01/31/logging-your-instances-history-in-django/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 23:30:14 +0000</pubDate>
		<dc:creator>cyril</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://savetheions.com/wp/?p=97</guid>
		<description><![CDATA[History tables? While working on a rewrite of one of our web app here at AUF, I needed to replicate a logging functionality. The old system was written with php4 (please don&#8217;t barf on your screen), and so you can imagine how such a thing could have been done: Get current entry in the table. [...]]]></description>
			<content:encoded><![CDATA[<h1>History tables?</h1>
<p>While working on a rewrite of one of our web app here at <a href="http://auf.org" target="_blank">AUF</a>, I needed to replicate a <i>logging</i> functionality.</p>
<p>The old system was written with php4 (please don&#8217;t barf on your screen), and so you can imagine how such a thing could have been done:</p>
<ol>
<li>Get current entry in the table.</li>
<li>Generate an insert query to save that version of the entry in the <i>history</i> table.</li>
<li>Perform the update on the main table.</li>
</ol>
<p>Being lazy, as all programmers are, I looked around for an existing django app to do that, and I found <a href="http://code.google.com/p/django-history-tables/" target="_blank">django-history-tables</a>, which does exactly what I need!</p>
<p>Long story short, the latest release was for django 0.96, which is pretty old, and so I had to modify it a bit to make it work on 1.1.1, and later on, I found out that it was really unstable on slightly complex models. Please note that this is by no means criticism towards django-history-tables&#8217; author. I failed at fixing it.</p>
<p>So, what happens next? When the only solution I have fails, I have to buid one! Yay!</p>
<h1>The concept</h1>
<p>I figured the easiest way to this would require a couple of things:</p>
<ul>
<li>The model for the history table must be created by a syncdb</li>
<li>It must be relatively easy to use</li>
</ul>
<p>I decided then to start writing an abstract <code>History</code>, whose only job is to define a generic-enough saving method.</p>
<p>Here&#8217;s what it looks like</p>
<pre class="prettyprint">#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.db import models
from django.db.models.base import ModelBase
from django.db import connection, transaction
from copy import deepcopy
from datetime import datetime

class History (models.Model):
    history_datetime = models.DateTimeField(default=datetime.now)
    history_objectid = models.PositiveIntegerField()
    history_revision = models.PositiveIntegerField()
    history_comment = models.CharField(max_length=1024, default="")

    def save_log (self, instance):
        iClass = instance.__class__
        hClass = self.__class__

        # Reload the instance from db
        instance = iClass.objects.get(id = instance.id)
        self.history_objectid = instance.id
        self.history_comment = "pre_save history item &lt;%s&gt;" \
                % (repr(instance))
        self.history_revision = \
            hClass.objects.filter(history_objectid=instance.id).count()+1

        for field in instance._meta.fields:
            if field.__class__.__name__ != 'AutoField':
                if getattr(field, 'unique', False):
                    field._unique = False
                setattr(self, field.name, getattr(instance, field.name))

        super (History, self).save ()

    def save (self):
        pass

    class Meta:
        abstract = True
</pre>
<p>This class is pretty straightforward, the only odd thing is with the <code>save</code> method. I had to do this little hack because the rows in the history table would end up duplicated.</p>
<h1>Usage</h1>
<p>I think the best way to explain usage is by showing an example:</p>
<pre class="prettyprint">from django.db import models
from django_historique import History
from django.db.models.signals import pre_save, pre_delete

class Brand (models.Model):
    nom = models.CharField (max_length = 32)

    def __unicode__ (self):
        return "&lt;Brand %s&gt;" % self.nom

class CarBase (models.Model):
    marque = models.ForeignKey (Brand)
    couleur = models.CharField (max_length = 32)

    class Meta:
        abstract = True

class CarHistory (History, CarBase):
    def __unicode__ (self):
        return "&lt;CarH %s, rev. %s&gt;" \
                % (self.history_objectid, self.history_revision)

class Car (CarBase):
    id = models.AutoField (primary_key = True)
    def __unicode__ (self):
        return "&lt;Car %s&gt;" % self.id

def carhistory_save (sender, instance, signal, *args, **kwargs):
    history = CarHistory ()
    history.save_log (instance)
pre_save.connect(carhistory_save, sender=Car)
pre_delete.connect(carhistory_save, sender=Car)
</pre>
<p>A few comments:</p>
<ul>
<li>I do need to define an abstract <code>CarBase</code> that doesn&#8217;t include the id first, otherwise, django&#8217;s ORM screams that it&#8217;s not unique in the aggregate <code>CarHistory</code> class.</li>
<li>The <code>pre_save</code> and <code>pre_delete</code> are what django offers us to execute actions before saving and deleting instances.</li>
</ul>
<h1>Issues</h1>
<p>I can save <code>ForeignKey</code> values, so you will need to add a <code>*History</code> class for your foreign items and work some kind of time-based logic to figure out which version of the foreign object your instance was referring to</p>
<p>I don&#8217;t support <code>ManyToMany</code> fields</p>
</p>
<p>I hope you enjoyed it, the source code will be published on monday at google code: <a href="http://code.google.com/p/django-historique/" target="_blank">django-historique</a></p>
]]></content:encoded>
			<wfw:commentRss>http://savetheions.com/2010/01/31/logging-your-instances-history-in-django/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

